The next iteration of scope
Zach the Mystic via Digitalmars-d
digitalmars-d at puremagic.com
Mon Mar 16 18:13:39 PDT 2015
On Monday, 16 March 2015 at 20:50:46 UTC, Marc Schütz wrote:
> On Monday, 16 March 2015 at 19:43:01 UTC, Zach the Mystic wrote:
>> 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
> }
More accurately,
// `return` is moved
ref int* payload(return scope ref S __this) {
return __this.payload_;
}
I think that if you need `return` to make it safe, there's much
less need for `scope`.
> 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.
That's fine, but then there's the argument that syntax sugar is
different from "real" functionality. To add it would require a
compelling use case.
My fundamental issue with `scope` in general is that it should be
the safe default, which means it doesn't really need to appear
that often. If @safe is default, the compiler would force you to
mark any parameter `return` when it detected such a return.
>> 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.
See above. With `return` being forced on the implicit this
parameter:
ref int* payload(return /*scope*/ ref S __this) { ... }
`return` covers the need for safety, unless I'm still missing
something.
> 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.
Same argument. Forgetting `return` in safe code == compiler
error. I think DIP25 already does this.
More information about the Digitalmars-d
mailing list