a design flaw in DIP1035, its remedy, and the implication for @system variables

Zach Tollen zach at mystic.yeah
Wed Apr 13 12:14:53 UTC 2022


[DIP1035](https://github.com/dlang/DIPs/blob/72f41cffe68ff1f2d4c033b5728ef37e282461dd/DIPs/DIP1035.md) has a design flaw in its current form.

Let us assume it has been implemented as described.

Let us assume a naive user has an `extern` variable, which we 
will use as the example for the whole illustration.
```d
extern int* x;
```
According to the DIP, since this variable could possibly hold an 
unsafe value, it is immediately promoted to a `@system` variable. 
Our naive user then tries to write to it in a `@safe` setting.
```d
void main() @safe {
     *x = 10; // error: @system variable x may not be accessed in 
@safe code
}
```
Even if the user reassigns the pointer to a safe value, thus 
making the actual value safe, the variable is forevermore 
interpreted by the compiler as `@system`.
```d
void fn() @safe {
     () @trusted { x = new int; }();  // we're @safe now, right?
     *x = 10; // error: @system variable x may not be accessed in 
@safe code
}
```
Promoting `x` to a `@system` variable has had the effect of 
basically making it unusable. Eventually, the user realizes that 
the only way solve the problem is to declare the original 
variable `@trusted`.
```d
@trusted extern int* x;
```
That's what he wanted the whole time. Indeed, that's what 
*everyone* who inadvertently initializes a variable to an unsafe 
value wants. No one ever wants a variable to become permanently 
unwieldy, just because it may have begun in an unsafe state.

Now let's imagine that a compiler writer realizes this is a 
common pattern, and wants to improve the error message. So he 
makes a special flag to mark unsafely initialized variables 
internally, to distinguish them from explicitly `@system` ones. 
The semantics don't change; it's just a clearer error.
```d
extern int* x;
@system int y;

void fn() @safe {
     x = new int; // error: unsafely initialized variable `x` 
cannot be accessed
                  //   in @safe code - try marking its declaration 
@trusted?
     y++;         // error: @system variable y may not be accessed 
in @safe code
}
```
We're almost there. The distinction between unsafely-initialized, 
and explicitly-`@system` variables is starting to be felt.

Finally, it dawns on the compiler writers that they've been 
abusing the user the whole time. They already knew, from the 
moment the variable was declared, that there was going to be a 
problem. They had an unsafely-initialized variable. They should 
have forced the user then and there to say whether it was 
`@trusted` or `@system`.
```d
extern int* x; // error: unsafely initialized variables must be 
explicitly
                //    annotated with `@trusted`, or `@system`
```
Boom. We have the real solution to unsafely-initialized global 
variables.

So that fixes the design flaw.

And it leaves us with a new interpretation of `@system` 
variables. Key points:

  - Implicitly inferring a variable to be `@system` is little more 
than a form of torture. The user *always* wanted `@trusted`.

  - Actual `@system` variables are rare, and never accidental. 
Being intentionally hard to use, they should only be given to 
people who ask for them directly.



More information about the Digitalmars-d mailing list