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.

Reply via email to