(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.

Reply via email to