The next iteration of scope

via Digitalmars-d digitalmars-d at puremagic.com
Mon Mar 16 13:50:45 PDT 2015


On Monday, 16 March 2015 at 19:43:01 UTC, Zach the Mystic wrote:
> On Monday, 16 March 2015 at 17:00:12 UTC, Marc Schütz wrote:
>> BUt there is indeed still some confusion on my side. It's 
>> about the question whether `this` should implicitly be passed 
>> as `scope` or not. Because if it is, scope members are 
>> probably useless, because they are already implied. I think I 
>> should remove this suggestion, because it would break too much 
>> code (in @system).
>
> I always tend to think of member functions as if they weren't:
>
> struct S {
>   T t;
>   ref T fun() return {
>     return t;
>   }
> }
>
> In my head, I just translate fun() above to:
>
> ref T fun(return S* __this) {
>   return __this.t;
> }
>
> Therefore whatever the scope of `__this`, that's the scope of 
> the return, just like it would be for any other parameter. Then:
>
> S s;
> s.fun();
>
> ... is really just `fun(s);` in disguise. That's why it's hard 
> for me to grasp `scope` members, because they seem to me to be 
> just as scope as their parent, whether global or local.

It works just the same:

struct S {
     private int* payload_;
     ref int* payload() return {
         return payload_;
     }
}

ref int* payload(scope ref S __this) return {
     return __this.payload_;    // well, imagine it's not private
}

Both the S.payload() and the free-standing payload() do the same 
thing.

 From inside the functions, `return` tells us that we're allowed 
to a reference to our payload. From the caller's point of view, 
it signifies that the return value is scoped to the first 
argument, or `this` respectively.

To reiterate, `scope` members are just syntactical sugar for the 
kinds of accessor methods/functions in the example code. There's 
nothing special about them.

> How a member could be scope when the parent is global is hard 
> for me to imagine.

The following is clear, right?

int* p;
scope int* borrowed = p;

That's clearly allowed, we're storing a reference to a global or 
GC object into a scope variable. Now let's use `S`, which 
contains an `int*` member:

S s;
scope S borrowed_s = s;

That's also ok. Doesn't matter whether it's the pointer itself, 
or something containing the pointer. And now the final step:

scope int* p2;
p2 = s.payload;          // OK
p2 = borrowed_s.payload; // also OK
static int* p3;
p3 = s.payload;          // NOT OK!

However, if `payload` were not the accessor method/function, but 
instead a simple (non-scope) member of `S`, that last line would 
be allowed, because there is nothing restricting its use. For 
members that the struct owns and want's to manage itself, this is 
not good. Therefore, we make it private and allow access to it 
only through accessor methods/functions that are annotated with 
`return`. But we could accidentally forget an annotation, and the 
pointer could escape. That's what the `scope` annotation on the 
member is fore.

Does that clear it up?


More information about the Digitalmars-d mailing list