On Wednesday, 25 February 2015 at 01:12:15 UTC, Zach the Mystic
wrote:
So what are these bits? Reserve 4 bits for an unsigned integer
(range 0-15) I call "scopedepth". Scopedepth is easier for me
to think about than lifetime, of which it is simply the
inverse, with (0) scopedepth being infinite lifetime, 1 having
a lifetime at function scope, etc. Anyway, a declaration's
scopedepth is determined according to logic similar that found
in DIP69 and Mark Schutz's proposal:
int r; // declaration scopedepth(0)
void fun(int a /*scopedepth(0)*/) {
int b; // depth(1)
{
int c; // depth(2)
{
int d; // (3)
}
{
int e; // (3)
}
}
int f; // (1)
}
You have element of differing lifetime at scope depth 0 so far.
Principle 5: It's always un@safe to copy a declaration scope
from a higher scopedepth to a reference variable stored at
lower scopedepth. DIP69 tries to banish this type of thing only
in `scope` variables, but I'm not afraid to banish it in all
@safe code period:
void gun() @safe {
T* t; // t's declaration depth: 1
T u;
{
T* uu = &u; // fine, this is normal
T tt;
t = &tt; // t's reference depth: 2, error, un@safe
}
// now t is corrupted
}
Bingo. However, when you throw goto into the mix, weird thing
happens. The general idea is good but need refining.
Principle 6: Reference variables: Any data which stores a
reference is a "reference variable". That includes any pointer,
class instance, array/slice, `ref` parameter, or any struct
containing any of those. For the sake of simplicity, I boil
_all_ of these down to "T*" in this proposal. All reference
types are effectively the _same_ in this regard. DIP25 does not
indicate that it has any interest in expanding beyond `ref`
parameters. But all reference types are unsafe in exactly the
same way as `ref` is. (By the way, see footnote [1] for why I
think `ref` is much different from `scope`). I don't understand
the restriction of dIP25 to `ref` paramteres only. Part of my
system is to expand `return` parameter to all reference types.
Bingo 2!
Principle 7: In this system, all scopes are *transitive*: any
reference type with double indirections inherits the scope of
the outermost reference. Think of it this way:
It is more complex than that, and this is where most proposals
fail short (including this one and DIP69). If you want to
disallow the assignment of a reference to something with a short
lifetime, you can't consider scope transitive when used as a
lvalue. You can, however, consider it transitive when used as an
rvalue.
The more general rule is that you want to consider the largest
possible lifetime of an lvalue, and the smallest possible one for
an rvalue.
When going through an indirection, that will differ, unless we
choose to tag all indirections, which is undesirable.
Principle 8: Any time a reference is copied, the reference
scope inherits the *maximum* of the two scope depths:
That makes control flow analysis easier, so I can buy this :)
Principle 8: We don't need to know! For all intents and
purposes, a reference parameter has infinite lifetime for the
duration of the function it is compiled in. Whenever we copy
any reference, we do a bitwise OR on *all* of the mystery
scopes. The new reference accumulates every scope it has ever
had access to, directly or indirectly.
That would allow to copy a parameter reference to a global, which
is dead unsafe.
There is some goodness in there. Please address my comment and
tell me if I'm wrong, but I think you didn't covered all bases.