www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - a design flaw in DIP1035, its remedy, and the implication for system

reply Zach Tollen <zach mystic.yeah> writes:
[DIP1035](https://github.com/dlang/DIPs/blob/72f41cffe68ff1f2d4c033b5728ef37e28246
dd/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.
Apr 13 2022
next sibling parent Dennis <dkorpel gmail.com> writes:
On Wednesday, 13 April 2022 at 12:14:53 UTC, Zach Tollen wrote:
 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`.
extern variables should be rare in D, they're usually the result of translated C code. Translated C code isn't ` safe`, so has no problem accessing ` system` variables. Introducing forced attributes seems more annoying to me than inferred ` system` variables.
Apr 13 2022
prev sibling next sibling parent Nick Treleaven <nick geany.org> writes:
On Wednesday, 13 April 2022 at 12:14:53 UTC, Zach Tollen wrote:
 ```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?
That would encourage people to use trusted even when it is actually an unsafe value. ...
 They should have forced the user then and there to say whether 
 it was ` trusted` or ` system`.
That would break existing code. system is a good default for extern (C) unsafe globals and functions, even if we make D safe by default.
Apr 13 2022
prev sibling parent Paul Backus <snarwin gmail.com> writes:
On Wednesday, 13 April 2022 at 12:14:53 UTC, Zach Tollen wrote:
 ```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;
 ```
Worth noting that this is not the *only* solution. One can also provide a ` trusted` interface using getter and setter functions; e.g., ```d extern int* x; // inferred system system bool initializedX = false; trusted void safeX(int* value) { x = value; initializedX = true; } trusted int* safeX() in (initializedX) { return x; } safe void fn() { safeX = new int; *safeX = 10; } ```
Apr 13 2022