On Sunday, 9 April 2017 at 20:14:24 UTC, Walter Bright wrote:
On 4/9/2017 1:16 AM, Daniel N wrote:
... but why not go all the way, making it "always" refcounted? (for any "new E",
not emplace).

Backwards compatibility, for one. For another, a general mechanism for safe refcounting of classes has eluded us.

Hi guys. Hey Walter. So, about this point. On the lifetime study thread, http://forum.dlang.org/post/[email protected] , the following two problems were stated by Andrei, but I don't think they were adequately addressed in the subsequent posts:

===
Widget global;
@rc class Widget {
   int x;
   void fun() {
     global = null;
     ++x;
   }
}

void main() {
   global = new Widget;
   global.fun();
}

In this example, if global has a refcount==1 upon entering fun(), the assignment "global = null" deletes the Widget object and ++x accesses dangling memory.

I should add here another pattern that turned problematic for our older attempts in DIP74:

C c = new C();
foo(c);

int foo(scope C d) {
     c = new C();    // c's old instance gets deleted
     return d.i;        // oops! d is invalid
}
===

So here's my analysis of both these problems.

When calling a function, the reference count for an object must increase by the total number of aliases created by the call — *minus the ones lost*. Globals are special in this regard, because access to them is not lost in the called function. Local variables, however, are lost to the called function — they cannot be accessed except through the new alias they receive as a parameter. Thus, only globals must modify the reference count when passed.

Thinking about this is made easier if we turn all accessible aliases into function parameters. For this, we need to consider the set of globals as a hidden parameter to the function. Any global is therefore already passed to all functions. If we pass it again via parameter, that amounts to two aliases, thus two references. The same logic applies, 1. to duplicating any given variable in the argument list, e.g. "fun(c, c);", 2. to duplicating the hidden 'this' parameter, 3. to recognizing and outer function's stack frame as an additional alias.

All these can be verified at compile time. Also, it is optimistic regarding the most common case, i.e. passing a local does not require increasing the reference count.

--Zach

Reply via email to