April 05, 2020
On 4/4/2020 1:09 AM, Jonathan M Davis wrote:
> Anything else would go against what @safe is supposed to be promising.

Extern declarations are the USER making promises. Even with extern (D), the return type isn't mangled into the name. The User has to get it right.
April 05, 2020
On 5/4/20 11:12, Walter Bright wrote:
> On 4/4/2020 1:09 AM, Jonathan M Davis wrote:
>> Anything else would go against what @safe is supposed to be promising.
> 
> Extern declarations are the USER making promises. Even with extern (D), the return type isn't mangled into the name. The User has to get it right.

I'm not a heavy user or a big contributor of D, but just my 2¢: I find this totally unexpected. To me as a non-guru it breaks the principle of least astonishment and I'm convinced it will just generate confusion and subtle bugs.

Of course the user can always explicitly mark functions as @system, but then I bet that more than 99% of the external declarations (without function body) will have to be tagged as such. Since Walter has always defended sane defaults, I think this is one prime case to apply this principle.

In fact, a new user who is not that adept at D and its subtleties, and that just wants to interact with a C library would find very surprising that his expected @safe code is no longer @safe *without even a warning*.

Even more, marking declarations without body as @system wouldn't even be an exception to any rule. The way I understand the different safety levels is the following (please correct me if wrong):

@safe: Memory safety has been proven and enforced by the compiler according to a know set of rules.
@trusted: Memory safety has been manually proven / promised by the user.
@system: Everything else.

If we follow this, marking *any* functions without body by default as @system would be the logical thing to do, because they haven't been proven neither by the compiler nor (by default, one would assume) by the user. Furthermore, it shouldn't be possible for such a function to ever be @safe, at most it should be @trusted.

In fact, assuming @safe would break the promise above!

The only exception would be then where the mangling already indicates this, as in "extern (D)". Since the mangling is already trusted, it would be no exception in this case.

Of course, there's the argument that the user should know that he has to do the verification for each function, and that by just putting the declaration there he is implicitly taking responsibility for the memory safety of the function, and that it's up to him to mark it as @system if needed.

But then, wouldn't that be an argument to assume everywhere @trusted by default? If the user is responsible for marking non-trusted function declarations, why not do the same for non-trusted function definitions?

Just assume that all function bodies are safe, and ask the user to slap @system on those who aren't!

Isn't that an inconsistency as well?

A.
April 05, 2020
On Sunday, 5 April 2020 at 09:12:21 UTC, Walter Bright wrote:
> Extern declarations are the USER making promises. Even with extern (D), the return type isn't mangled into the name. The User has to get it right.

Yes but :-)

The question is whether the language defaults help the user make the _right_ choices.  If the easy thing to do is to do nothing -- not add any attribute -- is it more likely that this will be a correct choice, or a false promise?

I'm actually starting to think that we're getting the idea of `@safe` back to front in this discussion.  As jmh530 pointed out earlier <https://forum.dlang.org/post/zxwazhgynudymqyueeyy@forum.dlang.org>, `@safe` is not a guarantee that the function is memory-safe: it's a request that the compiler validate that certain potentially-unsafe operations are not performed within the function body.

BY DEFINITION those checks cannot be performed on functions where we do not have the body.

So even if we ask for the checks of `@safe` to be on by default, there is nothing for them to validate in the case of external functions where we only have the signature.

So it falls out quite naturally for the compiler to say here, "I can't validate this, so you have to tell me explicitly whether it is `@system` or `@trusted`".  (Or perhaps to assume `@system` until explicitly told otherwise.)

The one exception would be external D functions where the mangling tells us they are `@safe`, where it would be reasonable to assume that those were checked when the library concerned was compiled.

(This is by the way exactly what jmh530 already said, but I thought I'd emphasize it:-)
April 05, 2020
On 5/4/20 11:50, Arafel wrote:
> But then, wouldn't that be an argument to assume everywhere @trusted by default? If the user is responsible for marking non-trusted function declarations, why not do the same for non-trusted function definitions?
> 
> Just assume that all function bodies are safe, and ask the user to slap @system on those who aren't!
> 
> Isn't that an inconsistency as well?

To expand on this final point, I think it's quite important. Consider this:

```d
extern(C) void foo(); /* assumed @safe, or more properly, @trusted- */
extern(C) void bar() { } /* assumed @system, why not @trusted as well? */

void main() @safe {
    foo(); // OK: Here we assume the user verified the function
    bar(); // ERROR: Here we don't!!
}
```

Don't you find this inconsistent and confusing? For sure I do.

A.
April 05, 2020
On 5/4/20 12:06, Arafel wrote:
> ```d
> extern(C) void foo(); /* assumed @safe, or more properly, @trusted- */
> extern(C) void bar() { } /* assumed @system, why not @trusted as well? */
> 
> void main() @safe {
>      foo(); // OK: Here we assume the user verified the function
>      bar(); // ERROR: Here we don't!!
> }
> ```
> 
> Don't you find this inconsistent and confusing? For sure I do.
> 
> A.

My bad, in this case bar() would be assumned @safe and verified as well, and it would work. A better example would be:

```c
void foo(int **i) { /* assumed @trusted! */
    *i = 0xDEADBEEF;
}
```

```d
extern(C) void foo(int **i); /* unsafe, but assumed @safe, or more properly, @trusted- */
extern(C) void bar(int **i) { /* properly checked, why not assume the user did it? */
    *i = cast (int *) 0xDEADBEEF;
}

void main() @safe {
    int **i;
    foo(i); // OK: Here we assume the user verified the function
    bar(i); // ERROR: Here we don't!!
}
```
April 05, 2020
On Sunday, April 5, 2020 3:12:21 AM MDT Walter Bright via Digitalmars-d wrote:
> On 4/4/2020 1:09 AM, Jonathan M Davis wrote:
> > Anything else would go against what @safe is supposed to be promising.
>
> Extern declarations are the USER making promises. Even with extern (D), the return type isn't mangled into the name. The User has to get it right.

Sure, the user has to get the declaration right, but @safe is about the compiler verifying code for memory safety, and in the case of extern(C) declarations, it has not done that. IMHO, it's not even appropriate for a programmer to put @safe on an extern(C) declaration, and it should be illegal, because the compiler didn't verify it. If the programmer verified it, then they should be using @trusted. And this DIP will end up having the compiler slap @safe on it even though it hasn't verified anything.

Right now, if a programmer doesn't mark an extern(C) declaration with @system, it's still treated as @system (and thus unverified by either the programmer or the compiler), and there are no @safety problems. When the function is used in @safe code, the fact that declaration is @system will be flagged as an error, and either the programmer will determine that it can be @trusted (and thus explicitly mark it as @trusted), or the code using it will have to do stuff in a way that _it_ can be @trusted. Either way, you don't end up with code with memory safety bugs being treated as @safe unless the programmer screws up with @trusted.

After this DIP, if the programmer screws up and forgets to mark an extern(C) declaration as @system, the compiler will happily treat it as @safe even though neither the programmer nor the compiler has verified it for memory safety. And voila, the programmer's screw-up caused a bug in the code instead of being caught by the compiler, whereas with the current behavior, the compiler would catch it and force the programmer to verify the code for @safety. With this DIP, the programmer can no longer rely on @safe code being memory safe so long as @trusted was not incorrectly applied.

Arguably even worse, all of the existing extern(C) declarations out there which currently are quite reasonably left unmarked and treated as @system will suddenly be treated as @safe. Code which worked perfectly fine before will break. This DIP effectively breaks _all_ existing non-extern(D) declarations which have not explicitly been marked as @system or @trusted, and it does so invisibly. To deal with this, every D library and program will have to have be searched for declarations which are not extern(D) so that they can be marked with @system - something that the compiler really should be doing - and invariably, some of them will fall through the cracks and introduce @safety bugs.

I really don't understand your position on this. It's so simple and straightforward to just treat all declarations which are not extern(D) as @system by default, and there's _no_ downside to it from the standpoint of anyone who isn't a compiler dev. On the contrary, it maintains the default that all non-extern(D) declarations should have, because they haven't actually been verified by the compiler for memory safety, and it prevents bugs. Making @safe the default for non-extern(D) declarations will just introduce bugs rather than fix them. It solves nothing while being error-prone and introduing a hole into @safe at the same time that we're trying to improve it. From the standpoint of a programmer using the language, there is literally _no_ upside to treating extern(C) declarations as @safe by default. It just increases the odds that extern(C) declarations will be wrong and introduce bugs.

@safe is supposed to mean that the compiler verified the function for memory safety. @trusted is supposed to mean that the programmer verified it. And @system is supposed to mean that it's unverified. _Please_ don't change that.

- Jonathan M Davis



April 05, 2020
On 4/5/20 6:17 AM, Arafel wrote:
> ```d
> extern(C) void foo(int **i); /* unsafe, but assumed @safe, or more properly, @trusted- */
> extern(C) void bar(int **i) { /* properly checked, why not assume the user did it? */
>      *i = cast (int *) 0xDEADBEEF;
> }

Just to clarify, the DIP marks all functions @safe by default, which means bar will fail to compile.

In my proposal to change it, bar would compile, both it and foo would be marked @system (even in the cases where bar was actuallly @safe).

> 
> void main() @safe {
>      int **i;
>      foo(i); // OK: Here we assume the user verified the function
>      bar(i); // ERROR: Here we don't!!
> }
> ```

The compiler won't get this far, bar will fail first.

-Steve
April 05, 2020
On 4/5/20 5:12 AM, Walter Bright wrote:
> On 4/4/2020 1:09 AM, Jonathan M Davis wrote:
>> Anything else would go against what @safe is supposed to be promising.
> 
> Extern declarations are the USER making promises. Even with extern (D), the return type isn't mangled into the name. The User has to get it right.

But the user DID make a correct promise. Today, they promised "here's a C function, and it's @system". Changing the language to mean the opposite of what it means today is not the user breaking the promise, it's the compiler moving the goalposts.

-Steve
April 05, 2020
On Sunday, 5 April 2020 at 09:12:21 UTC, Walter Bright wrote:
> On 4/4/2020 1:09 AM, Jonathan M Davis wrote:
>> Anything else would go against what @safe is supposed to be promising.
>
> Extern declarations are the USER making promises.

Sorry but that is wrong. extern declarations is just that, it's a declaration of a call interface, nothing more. It tells how to call a function. It tells strictly nothing about the implementation of said function.
Assuming safety just by looking at the interface is completely bonkers.

All the safety issues in C come from relying on USER promises.


extern (C) void hello(int);

----------------------------

void hello(int o)
{
  system("format c:");
}


> Even with extern (D), the return type isn't mangled into the name. The User has to get it right.

Has no bearing with the problem of safety.
April 05, 2020
On 04.04.20 09:01, Walter Bright wrote:
> On 3/27/2020 2:02 PM, Jonathan M Davis wrote:
>> I don't know if we can reasonably change how @trusted is treated in name
>> mangling at this point, but I definitely think that it was a mistake to
>> distinguish between @safe and @trusted with name mangling.
> 
> If @trusted wasn't part of the mangling, one could not turn the mangling back into the function signature.

Jonathan's more general point was that there is no reason to distinguish @safe and @trusted in function signatures. In fact, it would be an improvement if @trusted functions had @safe function signatures.