Non-techincal brain, is @safe by default good or not?

Mathias LANG geod24 at gmail.com
Thu May 28 10:28:47 UTC 2020


On Thursday, 28 May 2020 at 07:30:28 UTC, Lutger wrote:
> On Wednesday, 27 May 2020 at 12:59:12 UTC, aberba wrote:
>
>> Now I hearing @safe by default which reads like the plan has 
>> changed and now the direction is going all-in on everything 
>> MUST BE SAFE. After reading the DIP, I getting a feeling I'll 
>> need to re-think my programming model to make everything safe. 
>> Sound in my understanding like most code will break. 
>> Communist/Socialist kind of coding.
>
> 'everyday programming' in D is almost certainly memory safe, 
> except for any c libraries you might use.

I write D on a daily basis. This is most certainly not my 
experience. I hear this claim over and over, yet I see no 
evidence of it being true. So could you substantiate your claim ?

Let me provide some substance to my own claim. Just right now, I 
tried to use Phobos' `std.bitmanip.BitArray`. A bit array is most 
certainly `@safe`, right ? Nope, absolutely not.

Okay, that module is old, let's use something that should be 
prominent: `std.json`:
```
import std.json;

struct MyCustomType
{
     public string toString () const @system { return null; }
     alias toString this;
}

void main () @system
{
     JSONValue json;
     MyCustomType ilovedlang;
     json = ilovedlang;
}
```

Results in:
```
/usr/local/opt/dmd/include/dlang/dmd/std/json.d(459): Error: 
@safe function std.json.JSONValue.assign!(MyCustomType).assign 
cannot call @system function foo.MyCustomType.toString
foo.d(5):        foo.MyCustomType.toString is declared here
/usr/local/opt/dmd/include/dlang/dmd/std/json.d(593): Error: 
template instance std.json.JSONValue.assign!(MyCustomType) error 
instantiating
foo.d(13):        instantiated from here: opAssign!(MyCustomType)
```

But... WHY ? My main is `@system`, why do I get a `@safe` error 
when I just want to prototype something (in practice, I would not 
put any attribute on `toString` but wanted to drive the point 
home). Well because someone decided that `std.json` should be 
`@safe` and we can't compose attributes easily (as explained 
before). Well that right here is our future with `@safe` by 
default.

But surely we achieved `@safe`ty, you think ? Well, at what 
expense ? If you look at the implementation of `std.json` 
(https://github.com/dlang/phobos/blob/5ebf458b509963725e1143b733fba1b22f22ed3f/std/json.d#L450-L533) you'll see that it essentially have to duplicate all its argument to ensure safety (otherwise alias this to function would defeat it). Including associative arrays.

And yet... No we're not `@safe` yet. Some methods (including 
`opApply`) are `@system`, which means things like:
```
import std.json;

void main () @safe
{
     JSONValue json;
     json = [ "Un", "Deux", "trois", "quatre" ];
     foreach (idx, val; json.array) { }
}
```

Are not `@safe`. You can see it for a few other functions (e.g. 
`object`).

  Pick any module in Phobos, and you will find one of three things:
- It is trivial (no user callback, only value types, etc...)
- It can only be used by either `@system` or `@safe` users, not 
both;
- It is either overly `@trusted` or everything under the sun is 
templated;

Bonus point:
I kinda wanted to find a `@safe`ty failure in Phobos to 
illustrate things better.
`std.json` unfortunately looked fairly solid (because of how 
limited it is), so I went to the catch-all: `std.algorithm`, more 
precisely `std.algorithm.mutation`, because, you know, mutation.
So here we go:
```
import std.algorithm.mutation;
struct S
{
     void opPostMove(const ref S old) @system nothrow pure
     {
         int* ptr = cast(int*)42;
         *ptr = 42;
     }
     int a;
}
void main () @safe nothrow
{
     S s1;
     s1.a = 41;
     S s2 = move(s1); // BOOM
     assert(s2.a == 42);
}
```

This compiles and crash just fine.


More information about the Digitalmars-d mailing list