April 05, 2020
On 4/5/2020 12:22 PM, Timon Gehr wrote:
> I really doubt that. It's a simple rule. The version that is easiest to implement is you simply disallow extern(C) functions without body to be marked @safe. It's a single `if` statement in an appropriate place.

Famous last words.

Just look at the swamp of misery from "simple" C rules, such as their effect on C++ overloading. The quagmire got a lot worse when C++ added type inference. I attended a Scott Meyers talk that was a full hour long just on the weird special cases forced on C++ due to those simple rules. Companies pay Scott a boatload of cash for these lectures.

I wouldn't be surprised if more than half of the bugs in bugzilla are the result of an unexpected interaction between simple exceptions to rules.

I've been around this block a few thousand times. Remember, it ain't just the compiler. The users don't remember these exceptions. Every one of them makes the language harder to learn and master.
April 06, 2020
On Monday, 6 April 2020 at 02:43:51 UTC, Walter Bright wrote:
> On 4/5/2020 12:22 PM, Timon Gehr wrote:
>> I really doubt that. It's a simple rule. The version that is easiest to implement is you simply disallow extern(C) functions without body to be marked @safe. It's a single `if` statement in an appropriate place.
>
> Famous last words.
>
> Just look at the swamp of misery from "simple" C rules, such as their effect on C++ overloading. The quagmire got a lot worse when C++ added type inference. I attended a Scott Meyers talk that was a full hour long just on the weird special cases forced on C++ due to those simple rules. Companies pay Scott a boatload of cash for these lectures.
>
> I wouldn't be surprised if more than half of the bugs in bugzilla are the result of an unexpected interaction between simple exceptions to rules.
>
> I've been around this block a few thousand times. Remember, it ain't just the compiler. The users don't remember these exceptions. Every one of them makes the language harder to learn and master.

I fail to understand how you are not seeing it as a problem, provided every single other person on this thread has. And consensus isn't easily achieved in the D community (or any community, for that matter), but it seems that here, even if opinions on `@safe` & `@trusted` differ, everyone agrees that have `extern` functions without D linkage `@safe` by default is a bad idea. Surely the voice of all the long standing D contributors have to carry some weight ?

Regardless, it doesn't have to be a rule. Just make it a compiler error. E.g. `extern(C) void foo();` leads to: "Error: `extern(C) void foo()` needs to be explicitly marked as `@system` or `@trusted`".
If you don't want this error message, then let it be `@system`, and the compiler will complain with "Error: `@safe` function `...` cannot call system function `...`" and hopefully that'd be clear enough.

You're right that `extern` rely on the user declaring things correctly to work. However, having the extern declaration potentially mis-attributed by default is a sure way to shoot oneself in the foot. By setting the default of `extern` (non D linkage) functions to `@system`, OR by requiring users to explicitly mark the prototype one way or the other, at least the user has to *actively* make the mistake.
April 06, 2020
On Monday, 6 April 2020 at 02:23:03 UTC, Walter Bright wrote:
> On 4/5/2020 12:22 PM, Timon Gehr wrote:
>> Right. How can you claim that this is @safe code?
>
> Extern declarations are always going to rely on the user declaring them correctly. It's an inherent property of a language that supports separate compilation.

But correctly is not a black-and-white thing, it's a spectrum.
Take `memcpy` for example. Its prototype in C is:
```
void* memcpy(void *restrict dst, const void *restrict src, size_t n);
```

In druntime, it is:
```
extern (C):
@system:
nothrow:
@nogc:
void* memcpy(return void* s1, scope const void* s2, size_t n) pure;
```
https://github.com/dlang/druntime/blob/eb6911eeb4f632d42abe4e28f5030158c9e7af52/src/core/stdc/string.d#L42

Now what happens if we omit *any* of those attributes:
- `nothrow`: Can't call it from a `nothrow` function without a try/catch. So we *know* it does not throw, but the function doesn't guarantee it, so we are restricted in the way we call it.
- `@nogc`: Can't call it from a `@nogc` function. We also *know* it is `@nogc`, but the function doesn't expose that.
- `pure`: Same thing. While the function is `pure`, the lack of attribute *restricts usage*.
- `scope` on parameter: Same thing, usage is *restricted* to passing points which are not scope.
- A lack of `const` is also restrictive, because `const` is the loosest modifier (as mutable and immutable both implicitly convert to `const`)
- `return` is the *only* one that can cause trouble, because not adding it allows escaping a reference to a local variable.

So as long as I don't forget `return` on the first argument, and get the arguments type right, I won't violate *any* promise of the language even by forgetting to add `nothrow`, `@nogc` or `scope`. And even forgetting `const` will not violate any promise of the language, it will just restrict my usage.
April 06, 2020
On 06.04.20 04:43, Walter Bright wrote:
> On 4/5/2020 12:22 PM, Timon Gehr wrote:
>> I really doubt that. It's a simple rule. The version that is easiest to implement is you simply disallow extern(C) functions without body to be marked @safe. It's a single `if` statement in an appropriate place.
> 
> Famous last words.
> 
> Just look at the swamp of misery from "simple" C rules, such as their effect on C++ overloading. The quagmire got a lot worse when C++ added type inference. I attended a Scott Meyers talk that was a full hour long just on the weird special cases forced on C++ due to those simple rules. Companies pay Scott a boatload of cash for these lectures.
> 
> I wouldn't be surprised if more than half of the bugs in bugzilla are the result of an unexpected interaction between simple exceptions to rules.
> 
> I've been around this block a few thousand times. Remember, it ain't just the compiler. The users don't remember these exceptions. Every one of them makes the language harder to learn and master.

Moving goal posts. Your claim was it's hard to implement. The remainder of the post you quoted selectively out of context already refutes your argument comprehensively.
April 06, 2020
On Monday, 6 April 2020 at 00:54:16 UTC, Adam D. Ruppe wrote:
> On Monday, 6 April 2020 at 00:09:41 UTC, Jonathan Marler wrote:
>> Now, as to what to do. I spent a few minutes and added
>> `@safe:` in to the source files in druntime for windows, posix,
>> and linux. Done.
>
> That's my preferred solution to all this. It is a breaking change but much less of one. I wrote about it a few months ago in my blog:
>
> http://dpldocs.info/this-week-in-d/Blog.Posted_2020_01_13.html#my-attribute-proposal---no-changes-to-defaults

Yeah, I'd like to see projects start doing this and report back what bugs it found and how it improved code.  Would be great to get some data on the benefits of "@safe by default" in the real world.

April 06, 2020
On Monday, 6 April 2020 at 02:43:51 UTC, Walter Bright wrote:
> On 4/5/2020 12:22 PM, Timon Gehr wrote:
>> I really doubt that. It's a simple rule. The version that is easiest to implement is you simply disallow extern(C) functions without body to be marked @safe. It's a single `if` statement in an appropriate place.
>
> Famous last words.
>
> Just look at the swamp of misery from "simple" C rules, such as their effect on C++ overloading. The quagmire got a lot worse when C++ added type inference. I attended a Scott Meyers talk that was a full hour long just on the weird special cases forced on C++ due to those simple rules. Companies pay Scott a boatload of cash for these lectures.
>
> I wouldn't be surprised if more than half of the bugs in bugzilla are the result of an unexpected interaction between simple exceptions to rules.
>
> I've been around this block a few thousand times. Remember, it ain't just the compiler. The users don't remember these exceptions. Every one of them makes the language harder to learn and master.

I agree that every language needs to be very careful with complex rules.  But I don't see this as a complex rule, I would word it like this:

    treat "the code" inside "code blocks" as @safe unless explicitly marked as @system

Note that this would exclude function declarations themselves, as they are not "code", but instead, wrappers to executable code that comes from somewhere else and cannot be verified to be "@safe".  Whereas a function with a body (i.e. a code block) would be treated as @safe, namely, because the compiler can verify it is safe.

I think the rule is simple when you know the right way to define it.  I don't see any exceptions or "ifs", just a simple straightforward rule.


I would like to add however that I don't see you using this same "the rule is too complex" argument on DIP1032. Which would read something like this:

    function and delegate pointer types use the attributes that are listed, except when the type declarations themselves are function parameters or defined inside a function; in which case they would inherit all attribute from their contining function. (question: would nested functions also inherit attributes?).  Although, if the type itself is defined outside the function and only an alias is used to declare a pointer inside the function then it will not inherit the attributes from the containing function

I also have a low confidence that covers all the complexity this rule would require, but that's what I came up with so far.  That rule seem much more complex to me, and the only benefit I see is saving some tokens on some function/delegate type declarations, which I don't see come up too often anyway.  From my end it looks like you aren't applying the same rules to every proposal, rather, you're selectively cherry-picking arguments for each individual one.

April 06, 2020
On 4/5/20 9:28 PM, Jonathan M Davis wrote:
[snip]

I'm not disagreeing with any of this. Technically, @safe doesn't make sense on a C prototype.

But practically, preventing it doesn't buy us anything important. If you have a @safe extern(C) function (implemented in D), and it switches to @system, searching for @trusted to find its prototypes isn't the way to do it, you search for the function name. And technically, the @safe marking is correct, if the function is being checked.

There are a lot of rules in D which are technically sound, but result in pain and suffering in actual usage.

e.g:

static if(someBool)
   return x;
return y; // error statement not reachable

inout int[] arr;
writeln(arr); // OK
writeln(arr.filter!(a => a %5 == 0)); // Error: only parameters or stack based variables can be inout

I don't want to add to this list.

-Steve
April 06, 2020
On 4/5/20 10:43 PM, Walter Bright wrote:
> On 4/5/2020 12:22 PM, Timon Gehr wrote:
>> I really doubt that. It's a simple rule. The version that is easiest to implement is you simply disallow extern(C) functions without body to be marked @safe. It's a single `if` statement in an appropriate place.
> 
> Famous last words.
> 
> Just look at the swamp of misery from "simple" C rules, such as their effect on C++ overloading. The quagmire got a lot worse when C++ added type inference. I attended a Scott Meyers talk that was a full hour long just on the weird special cases forced on C++ due to those simple rules. Companies pay Scott a boatload of cash for these lectures.

Is this really your argument? Do we need Scott Meyers to explain such "esoteric" compiler errors like:

Error: cannot call @system function memcpy from @safe function main.

I think this is not an hour-long talk, but a 10-second talk: "C functions aren't checked by the D compiler, so they are @system by default." Done.

I think possibly those folks are going to be much more vulnerable to the existing rules surrounding @trusted that many of the core D developers can't seem to get right.

@system by default extern(C) functions are literally the most understandable and correct part of the whole D @safe/@system/@trusted system. And you want to remove that. Please reconsider.

-Steve
April 06, 2020
On Monday, 6 April 2020 at 12:19:10 UTC, Steven Schveighoffer wrote:
> On 4/5/20 9:28 PM, Jonathan M Davis wrote:
> [snip]
>
> I'm not disagreeing with any of this. Technically, @safe doesn't make sense on a C prototype.
>
> But practically, preventing it doesn't buy us anything important. If you have a @safe extern(C) function (implemented in D), and it switches to @system, searching for @trusted to find its prototypes isn't the way to do it, you search for the function name. And technically, the @safe marking is correct, if the function is being checked.

It does make sense for a extern(C) D-defined function indeed. I think when it comes to an extern(C) function declaration that's linked to a C function, in that case @safe doesn't really make sense since the body cannot be verified - which is what i believe is meant.


>
> There are a lot of rules in D which are technically sound, but result in pain and suffering in actual usage.
>
> e.g:
>
> static if(someBool)
>    return x;
> return y; // error statement not reachable
>
> inout int[] arr;
> writeln(arr); // OK
> writeln(arr.filter!(a => a %5 == 0)); // Error: only parameters or stack based variables can be inout

I'm not sure those are technically sound. Maybe more incomplete implementations of the features?

>
> I don't want to add to this list.
>
> -Steve


April 06, 2020
On 06.04.20 01:38, Steven Schveighoffer wrote:
> On 4/5/20 3:57 PM, tsbockman wrote:
>> On Sunday, 5 April 2020 at 19:22:59 UTC, Timon Gehr wrote:
>>> That makes no sense at all. You are arguing in favor of _@trusted_ by default! It should not even be _possible_ to mark an extern(C) function @safe, it has to be either @system or @trusted. The compiler does not do any checking here.
>>
>> I agree completely with this: it should be a compile-time error to declare a bodyless extern(C) function @safe, regardless of whether it is done implicitly by default, or explicitly with an annotation.
>>
>> The only distinction between @safe and @trusted is the compiler verification of the safety of a function's implementation. If that compiler verification wasn't done, then @safe cannot rightly apply.
>>
>> If having a different implicit default for bodyless extern(C) functions is too complicated, then just don't have a default for them at all: require all such declarations to be explicitly annotated either @system or @trusted.
> 
> I disagree with disallowing @safe as a specific marking on extern(C) code. You can write @safe extern(C) functions in D, and it makes no sense to require that they are @trusted at the prototype.

The linker can hijack them. The function signature of a @trusted function should be @safe anyway.

> Assuming @safe, no. Explicitly @safe OK, you marked it, you own it.
> ...

@safe:

// a lot of code
// ...

extern(C) corrupt_all_the_memory();

When did @safe become a matter of "it's your own fault if you shoot yourself in the foot, this memory corruption you are having is a good thing because it will teach you not to make more mistakes in the future"? If something may break @safe-ty as it trusts the programmer to get it right, it ought to be @trusted.


> We have similar problems with inout -- preventing obvious incorrect cases makes sense, until it doesn't.

This is not analogous. Here, the problem is that the "obvious incorrect cases" where not actually incorrect.

> I wish now I could go back and change what I thought, but unfortunately I'm not well-versed in the compiler to make the changes myself.
> 
> -Steve
I think you can just grep for the error messages and then remove the checks.