[Dlang-study] [lifetime] Initial thoughts on lifetime management
Michel Fortin
michel.fortin at michelf.ca
Wed Oct 28 04:24:46 PDT 2015
Le 27 oct. 2015 à 20:45, Andrei Alexandrescu <andrei at erdani.com> a écrit :
> * do not inherit Object. (Do we want a root of all @rc classes called RCObject?)
>
> * cannot be converted to interfaces (we may later add @rc interfaces)
This is actually how things work for D/Objective-C. And it does work. Assuming you want to allow multiple implementations of reference counting, you could have a different root object for each.
> * embed an implementation-defined reference count as a hidden member
Language-wise, you don't even need to bother about that. Since you have a root class, how the counting mechanism works is a root-class implementation detail. (IMHO)
> * have a vptr only if they define non-final methods (in particular, I think we should disable "synchronized" for them - it seems an unnecessary complication at least for v1)
If you want the root-class implementation to be able to jettison all the bagage, I'm sure that can be done. But this has nothing to do with reference counting and lifetime management, does it?
> * should they have a hidden pointer to the parent scope if nested?
The question is who owns who? Should the object retain its parent scope, or should the parent scope retain its object? One thing is sure: if you create a cycle, one of the two must be a weak (non-retaining) pointer. Which one probably depends on the situation. Perhaps just disallow non-static nested @rc classes.
> Each reference to the class behaves as-if there is a corresponding bump in reference count for it. This is maximally conservative, meaning even method calls need to make sure there's a refcount bump for "this".
True. Note that "each reference" must also counts temporaries. So if you have this:
foo(getObject());
what you really have is this:
foo(getObject(){-1});
where {-1} is a notation I made up to denote that the counter of the object returned by getObject() is decremented at the end of the statement. (The returned value is already {+1} by the caller.)
And if you have this:
c = getObject();
it becomes this:
c{-1}{+1} = getObject(){-1};
where the value assigned for c gets incremented during assignment, and both the old value for c and the temporary counters get decremented afterwards. (To be safe, the increments must be done before the decrements.) Since we have both a {+1} and a {-1} for the same object, they can be elided:
c{-1}{} = getObject(){};
It's actually easier to reason about how it works with temporaries because temporaries do not mutate. When you elide pairs, you have to follow the object reference, which is the value and not the variable. If we're to discuss this, we need a proper notation to annotate values in code like this:
void swap(ref C a, ref C b) {
C tmp = a;
a = b;
b = tmp;
}
--
Michel Fortin
michel.fortin at michelf.ca
https://michelf.ca
More information about the Dlang-study
mailing list