Proposal 2: Exceptions and @nogc

MysticZach via Digitalmars-d digitalmars-d at puremagic.com
Tue Apr 11 10:24:48 PDT 2017


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/56301A8C.1060808@erdani.com , 
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



More information about the Digitalmars-d mailing list