On Monday, 16 March 2015 at 13:55:43 UTC, Marc Schütz wrote:
Also, what exactly does the `scope` on T payload get you? Is
it just a more specific version of `return` on the this
parameter, i.e. `return this.payload`? Why would you need that
specificity? What is the dangerous operation it is intended to
prevent?
Nick already answered that. I'll expand on his explanation:
Let's take the RC struct as an example. Instances of RC can
appear with and without scope. Because structs members inherit
the scope-ness from the struct, `payload` could therefore be an
unscoped pointer. It could therefore be escaped
unintentionally. By adding `scope` to its declaration, we force
it to be scoped to the structs lifetime, no matter how it's
accessed.
If an RC'd struct is heap-allocated, but one of its members
points to the stack, how is it ever safe to escape it? Why
shouldn't the heap variable be treated as scoped too, inheriting
the most restricted scope of any of its members? To me, the
question is not how you can know that a member is scoped, so much
as how you could know that it *isn't* scoped, i.e. that a
sub-pointer was global while the parent was local. I think it
would require a very complicated type system:
struct S {
T* p;
}
// note the elaborate new return signature
T* fun(return!(S.p) S x) {
return x.p;
}
T* run() {
S s;
s.p = new T; // s local, s.p global
return fun(s);
}
The above is technically safe, but the question is whether it's
too complicated for the benefit. In the absence of such a
complicated system, the safe default is to assume a struct is
always as scoped as its most scoped member (i.e. transitive
scoping). Your idea of `scope` members would only be valid in the
absence of this safe default. But even then it would be of
limited usefulness, because it would prevent all uses of global
references in those members, even if the parent was global. For
me, it comes down to that you can't know if anything is global or
local until you define an instance of it, which you can't do in
the struct definition.