Feedback Thread: DIP 1028--Make @safe the Default--Final Review

jeckel jeckel12381236 at gmail.com
Sat Apr 11 16:21:22 UTC 2020


The extern(C) and friends should be @system by default. It is a 
special case, the intention is to make the unsafe code harder to 
use. Just like with () @trusted { ... }().

While all extern  declaration can't be verified as being safe, 
this is especially true for extern(C) and extern(C++). As the 
mangling does not have whether it was @safe or not, unlike 
extern(D). Yes you can still use an extern(D) declaration that is 
unsafe, but that is exactly why this is an unsafe feature that 
shouldn't be allowed in the first place. For a language that 
prioritizes safety.

Take Rust for example. It has no header files, there are no 
"declarations", other than C. Cargos are a first class citizen, 
and is much safer as a result not relying on user error with 
declarations. Declarations to C are unsafe by default. Rust 
doesn't have a "safe"/"trusted" keyword, so they cannot be 
implied to be "safe". They are *always* unsafe.

Pointing to extern(D) and saying that's unsafe as well, so we 
should make extern(C) unsafe too. That's a very bad rationale. We 
should fix extern(D) as well to actually be @safe, like with what 
Rust has done. We shouldn't introduce more @unsafe code because 
something in D is already unsafe.

The declaration itself is what is unsafe. That's why Rust has 
done away with them with Cargo, other than C declarations which 
default to unsafe. This is where a separe compilation model is 
inherently @unsafe. That doesn't mean because one thing that is 
already unsafe, should continue to be unsafe.

I can guarantee you there's more extern(C) @unsafe code out there 
than there is extern(C) @safe code. So it makes sense to make 
extern(C) @unsafe by default, as that is most definitely the 
common case. If that's the kind of rationale you are trying to 
impose onto extern(C) of why it should be @safe by default. It 
large majority of extern(C) code is most definitely not @safe. 
Otherwise citation required.

It's not surprising if a declaration has different attributes 
than it's definition. If it was, it'll be extremely easy to 
figure out. If you use an extern(C) declaration in @safe code, 
you'll get an error saying it isn't safe and needs to be 
explicitly annotated. There's no gotcha, no surprise down the 
line when a bug shows itself. In comparison if there's an unsafe 
extern(C) function being used somewhere because extern(C) 
declarations can be defined *everywhere* including within the 
body of a function.

Even though currently `@safe:` "flows through", it doesn't for 
extern(C) declarations.

     @safe:

     void test() {
         extern(C) void foo();
         foo(); // error calling @system function

         extern(C) void foo2() {
             // this is @safe
         }
         foo2(); // ok foo2 is @safe
     }

https://godbolt.org/z/ppsXMG

Even Walter of old knew better than to make extern(C) 
declarations implicitly @safe.

The case with nothrow is pretty simple. C doesn't have exceptions 
so it can always be nothrow. C++ has a nothrow equivalent and is 
included as part of the mangling, so that can be used for C++. So 
nothrow can simply be nothrow by default. It isn't that big of an 
issue as there isn't a case of calling a nothrow function and it 
actually being able to throw an exception. Even if there was, if 
an exception is thrown in a C++ nothrow function it simply 
terminates the application. Yes extern declarations are still 
terrible. It's something that was inherited from C and is 
something we should strive to remove, as Rust has done. Possibly 
in a future DIP.




More information about the Digitalmars-d mailing list