May 28, 2020
On 28.05.20 12:28, Mathias LANG wrote:
> 
> Results in:
> ```
> /usr/local/opt/dmd/include/dlang/dmd/std/json.d(459): Error: @safe function std.json.JSONValue.assign!(MyCustomType).assign cannot call @system function foo.MyCustomType.toString
> foo.d(5):        foo.MyCustomType.toString is declared here
> /usr/local/opt/dmd/include/dlang/dmd/std/json.d(593): Error: template instance std.json.JSONValue.assign!(MyCustomType) error instantiating
> foo.d(13):        instantiated from here: opAssign!(MyCustomType)
> ```
> 
> But... WHY ?

Indeed. Why is it even annotated? It would be inferred anyway...
May 28, 2020
On 5/28/20 6:28 AM, Mathias LANG wrote:
> 
> import std.algorithm.mutation;
> struct S
> {
>      void opPostMove(const ref S old) @system nothrow pure
>      {
>          int* ptr = cast(int*)42;
>          *ptr = 42;
>      }
>      int a;
> }
> void main () @safe nothrow
> {
>      S s1;
>      s1.a = 41;
>      S s2 = move(s1); // BOOM
>      assert(s2.a == 42);
> }
> ```
> 
> This compiles and crash just fine.

At least this is a legit bug report.
May 28, 2020
Am 28.05.20 um 12:28 schrieb Mathias LANG:
> ```
> import std.json;
> 
> struct MyCustomType
> {
>     public string toString () const @system { return null; }
>     alias toString this;
> }
> 
> void main () @system
> {
>     JSONValue json;
>     MyCustomType ilovedlang;
>     json = ilovedlang;
> }
> ```
> 
> Results in:
> ```
> /usr/local/opt/dmd/include/dlang/dmd/std/json.d(459): Error: @safe
> function std.json.JSONValue.assign!(MyCustomType).assign cannot call
> @system function foo.MyCustomType.toString
> foo.d(5):        foo.MyCustomType.toString is declared here
> /usr/local/opt/dmd/include/dlang/dmd/std/json.d(593): Error: template
> instance std.json.JSONValue.assign!(MyCustomType) error instantiating
> foo.d(13):        instantiated from here: opAssign!(MyCustomType)
> ```
>

Please file a bug report. `assign` is a template, it should not be explicitly annotated with @safe but instead the attributes should be inferred.

> ```
> import std.algorithm.mutation;
> struct S
> {
>     void opPostMove(const ref S old) @system nothrow pure
>     {
>         int* ptr = cast(int*)42;
>         *ptr = 42;
>     }
>     int a;
> }
> void main () @safe nothrow
> {
>     S s1;
>     s1.a = 41;
>     S s2 = move(s1); // BOOM
>     assert(s2.a == 42);
> }
> ```
> 
> This compiles and crash just fine.

Again, please file a bug report. This is either a bug with @safe or there is some @trusted in `move` (or one of the functions it calls) that calls `opPostMove`.

Both of the examples you provide are bugs but I realize that there are real examples of what you are trying to show. One situation where this happens is if libraries have non-template functions that take a callback as parameter. The library author has to make a decision whether to make his function @safe, which requires all callbacks passed to it also to be @safe, or to make it @system, which makes it unusable in @safe code, even if it actually is safe because the callback that was passed is @safe. @trusted allows both kinds of usages but is a really bad idea because it allows unchecked @system code to be called from @safe code.

This is why some people in the community have suggested to allow attribute inference also for non-template functions. That would solve the issue might might be a better default than both @system and @safe. However, I don't think anybody has thought that through completely yet. Some people have voiced concerns regarding inheritance and .di files (and probably more) but I think it might be possible to do this.
May 28, 2020
On Thursday, 28 May 2020 at 10:46:08 UTC, Andrei Alexandrescu wrote:
> On 5/28/20 6:28 AM, Mathias LANG wrote:
>> 
>> import std.algorithm.mutation;
>> struct S
>> {
>>      void opPostMove(const ref S old) @system nothrow pure
>>      {
>>          int* ptr = cast(int*)42;
>>          *ptr = 42;
>>      }
>>      int a;
>> }
>> void main () @safe nothrow
>> {
>>      S s1;
>>      s1.a = 41;
>>      S s2 = move(s1); // BOOM
>>      assert(s2.a == 42);
>> }
>> ```
>> 
>> This compiles and crash just fine.
>
> At least this is a legit bug report.

Well since you like it (filed as https://issues.dlang.org/show_bug.cgi?id=20869) I went ahead and did a quick search on trusted:
- https://issues.dlang.org/show_bug.cgi?id=20870
- https://issues.dlang.org/show_bug.cgi?id=20871
- https://issues.dlang.org/show_bug.cgi?id=20872
- https://issues.dlang.org/show_bug.cgi?id=20873

But as fun as it is to find those in Phobos, it's nothing in comparison of the language holes we still have. E.g. today Andrej had to track down a segfault: https://issues.dlang.org/show_bug.cgi?id=20868
May 28, 2020
On Thursday, 28 May 2020 at 11:07:16 UTC, Johannes Loher wrote:
>
> Again, please file a bug report. This is either a bug with @safe or there is some @trusted in `move` (or one of the functions it calls) that calls `opPostMove`.

Oh I know exactly how it happened. I just went over the code quickly, saw `@trusted`, and saw it calling a user-supplied hook, and crafting a test case was trivial.
This is because, at the top level, there is a function which checks if the destruction is `@safe` (well, it checks quite a few other things actually, but that's not the point here), and if it is, just blindly trust a lower function, which itself happens to be more correct in its usage of @trusted.

That's the technical explanation. The higher level explanation is that we had code that was written correctly, audited, then a language feature was added, and support for it was added by different contributors over time. And the *whole* code was not re-audited for `@trusted`.

> Both of the examples you provide are bugs but I realize that there are real examples of what you are trying to show. One situation where this happens is if libraries have non-template functions that take a callback as parameter. The library author has to make a decision whether to make his function @safe, which requires all callbacks passed to it also to be @safe, or to make it @system, which makes it unusable in @safe code, even if it actually is safe because the callback that was passed is @safe. @trusted allows both kinds of usages but is a really bad idea because it allows unchecked @system code to be called from @safe code.

Yes, that's a point I tried to make over and over, but it seems no one was interested.
And as mentioned, it also affects OOP code.
Slight correction though: Accepting a `@trusted` delegate will **not** allow you to pass a `@system` delegate. I tried.

> This is why some people in the community have suggested to allow attribute inference also for non-template functions. That would solve the issue might might be a better default than both @system and @safe. However, I don't think anybody has thought that through completely yet. Some people have voiced concerns regarding inheritance and .di files (and probably more) but I think it might be possible to do this.

That's a terrible idea:
- It will be a massive slowdown for anyone not compiling all-at-once: at the moment the frontend knows about "root module", which are module for which the compiler will do codegen. As such, it doesn't do any semantic analysis on functions that are not in root modules (except for the prototype). Inference for everything means you have to perform full semantic analysis for everything. Compiling by packages means performing full semantic for your whole program multiple times over. It also means whatever function in Phobos, every D program will also need to perform semantic analysis on them if it imports it. The compiler could (should) be smarter and have lazier semantic, but we need to implement it, and at the core, this suggestion does not scale.

- You would have to either disable that for OOP code, which would be a weird special case, or find a way to negate it, or ... ? I can't even picture a way to make this work. If you have a class, and your base implementation of `toString` just returns a literal, it has all attributes available, however derived code might want to use `format`.

- It doesn't solve the actual problem: You still will write your function prototype as `void requestHTTP(scope void delegate(scope ref HTTPRequest) /* @safe */ req)`.
You need to express a way to tie `requestHTTP`'s attributes to `req`'s attributes , not just infer `req`'s attributes. And the way you do this needs to be subtle, because you might want to express: "I am `@safe` is this is `@safe`" and "I am `nothrow` no matter what" as well as "I am not `@nogc` even if `req` is". At the moment we can express the second and the third variant but not the first.

IMO the real answer is to come up with something like `inout` for attributes. `inout` is a wildcard. It's exactly what you want for delegates. It doesn't solve the issue with OOP though, although it makes it easier to mitigate it (see `Throwable.toString` for how you could have a conditionally `@nogc` / `nothrow` / etc... method).
1 2
Next ›   Last »