New @safe rule: defensive closures

Dukc ajieskola at gmail.com
Thu Feb 15 14:48:56 UTC 2024


On Saturday, 28 May 2022 at 14:50:39 UTC, Steven Schveighoffer 
wrote:
>> 
>> Good brainstorming. But I don't think it can work:
>> 
>> ```D
>> void foo(ref int[5] arr)
>> { // It's not up to this function to decide where
>>    // arr resides in memory. Thus we can't make a
>>    // closure out of this one without breaking epected
>>    // behaviour.
>>    bar(arr[]);
>> }
>> ```
>> 
>
> Well, we have to decide if taking a value by ref means it 
> should be allocated, or if it should be scope (like DIP1000). 
> If we go with the latter, then you start getting error 
> messages, and we are kind of back to square one. If we go with 
> the former, then any simple use of struct methods is going to 
> allocate a closure.
>
> So yeah, that pretty much destroys this idea.
>
> -Steve

I'm necrobumping an old thread, because I made a discovery that I 
think brings this idea back to the table.

The closures we already have suffer from the same problem I wrote 
about here! Behold:

```D
int delegate(int) @safe escape1(scope int* x) @safe
{   return (int y) => *x += y;
}

int delegate(int) @safe escape2(ref int x) @safe
{   return (int y) => x += y;
}
```

These compile, but they shouldn't. They should require annotating 
their parameters with `return`. Now in itself this is just a 
DIP1000 bug, but consider the situation once it's fixed. If you 
create a pointer to a local variable and try to return it, you 
get an error, but if you create a delegate using it and return 
it, you get a closure. This is a language inconsistency for no 
good reason.

So we won't get rid of DIP1000 with this observation, but for 
sake of consistency maybe we still should reconsider the idea 
this thread is about.


More information about the Digitalmars-d mailing list