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