List of all permitted operations on scope function parameters.

Loara loara at noreply.com
Sun Apr 17 20:19:55 UTC 2022


On Sunday, 17 April 2022 at 12:35:25 UTC, user1234 wrote:
> On Sunday, 17 April 2022 at 08:57:40 UTC, Loara wrote:
>> On Friday, 15 April 2022 at 23:17:26 UTC, Salih Dincer wrote:
>>> On Friday, 15 April 2022 at 21:57:28 UTC, Loara wrote:
>>>> Documentation page 
>>>> https://dlang.org/spec/function.html#scope-parameters about 
>>>> `scope` function parameters says simply that a scoped 
>>>> parameter "can't escape that function's scope". This concept 
>>>> can be very tricky with some non-trivial algebra of struct's 
>>>> members and pointers, so I think it's better to provide a 
>>>> general algorithm to state if an expression/statement 
>>>> involving one or more `scope` function parameters is valid 
>>>> or not.
>>>
>>> **scope** and **return** are both my nightmare.  
>>> ```scope(exit) // blah blah```, no problem and even ```return 
>>> result``` It's okay...
>>>
>>> But when I come across these elsewhere, it's scary.  
>>> Especially in function parameters!
>>>
>>> @SDB79
>>
>> https://github.com/Loara/Rethink_scope_in_D/blob/main/README.md
>
> The first example you give is actually well rejected but only 
> in `@safe` code:
>
> ```d
> int* stack_allocate(size_t) @safe;
>
> void test() @safe
> {
>     scope int *a;
>     {
>         scope int *b = stack_allocate(1);
>         a = b;
>     }
> }
> ```
>
>> /tmp/temp_7F010929C2D0.d:8:11: Error: scope variable `b` 
>> assigned to `a` with longer lifetime
>
> it's not mentioned in the specs for `@safe` however.

It's not a compilation error, it's an incomplete documentation 
issue since if we follows only the official documentation this 
should compile, and it'll compile if we remove the innermost 
block (as explained in the next example). Making scope operation 
not transitive let it a cumbersome tool that force programmers to 
use a lot of casts.

Notice also that the preceding code will compile if we translate 
it to
``` d
import std.stdio;

extern int * stack_allocate() @trusted;

     int main() @safe{
         scope int *a;
         {
             scope int **b = new int *();
             *b = stack_allocate();
             a = *b;
         }
         return 0;
     }
```
because the `scope` storage class is not transitive.

The real question at this point is: we want to make `scope` only 
a tool in order to allow stack allocation, or we want to use it 
in order to avoid any indirection inside it to escape its scope 
(for example when we want to manage a `shared` object inside a 
synchronized block)?

I don't see at this moment any clear objective behind the `scope` 
attribute, any well defined purpose.

In the next articles I'll explain better the idea of a scoped 
block as a way to statically control which indirections escapes 
and which not.


More information about the Digitalmars-d mailing list