scope escaping

Marc Schütz" <schuetzm at gmx.net> Marc Schütz" <schuetzm at gmx.net>
Sat Feb 8 10:35:12 PST 2014


(I see now that Adam already talked about this in his second 
post, but I'm posting it anyway, as I suggest a different 
solution.)

On Thursday, 6 February 2014 at 15:47:44 UTC, Adam D. Ruppe wrote:
> c) Calling methods on a struct which may escape the scope is 
> wrong. Ideally, `this` would always be scope... in fact, I 
> think that's the best way to go. An alternative though might be 
> to restrict calling of non-pure functions. Pure functions don't 
> allow mutation of non-scope data in the first place, so they 
> shouldn't be able to escape references.

As a consequence of this, it would no longer be possible to 
manage an owned object that has a back-pointer to its owner, e.g:

class Window {
     Menu _menu;
     this() {
         _menu = new Menu(this);    // cannot pass `this`
     }
     ~this() {
         delete _menu;
     }
}

class Menu {
     Window _parent;
     this(Window parent) {
         parent = _parent;
     }
}

This can probably be solved somehow. Allowing `scope` as a type 
constructor and doing the following might work, but I'm not sure 
about the safety implications:

class Window {
     scope Menu _menu;
     this() {
         _menu = new Menu(this);    // `new` returns a scope(Menu)
     }
     ~this() {
         delete _menu;              // either explicitly or 
implicitly
     }
}

class Menu {
     scope Window _parent;
     scope this(scope Window parent) {
         parent = _parent;
     }
}

(Note that this assumes scope isn't the default.)

The trick is to recognize that we can basically treat 
constructors and destructors as having a scope that starts when 
the constructor is entered and ends when the destructor returns. 
`this` can be seen as being declared inside this scope.

For member fields, `scope` also means "owned". Therefore, it 
needs to be destroyed when the scope is left (which in this case 
means: when the object is being destroyed). Thinking about this 
some more, this might even be a good idea for local scope 
variables too. This would basically mean undeprecating `scope` 
for classes. Anyway, this behaviour guarantees that the reference 
no longer exists after the object is destroyed.

`this` must me marked as `scope`, which causes `new` to return a 
scoped reference. This necessary to keep it from being assigned 
to non-scope variables. Consider the following situation:

class Menu {
     scope Window _parent;
     scope this(scope Window parent) {
         parent = _parent;
     }
}

Menu a;
void foo(scope Window w) {
     a = new Menu(w);               // not good, trying to assign 
to non-scope
     scope Menu b = new Menu(w);    // ok
}

On the other hand, I already see at least one problem:

class SomeClass {
     scope SomeClass other;
}

void foo(scope SomeClass a) {
     scope SomeClass b = new SomeClass;
     a.other = b;    // ouch
}

In Rust this is solved by the concept of lifetimes, i.e. while 
both `a` and `b` are scoped, they have different lifetimes. It's 
disallowed to store a reference to an object with a shorter 
lifetime into an object with a longer lifetime.


More information about the Digitalmars-d mailing list