Improving DIP74: functions borrow by default, retain only if needed

Steven Schveighoffer via Digitalmars-d digitalmars-d at puremagic.com
Fri Feb 27 12:30:20 PST 2015


On 2/27/15 1:24 PM, Andrei Alexandrescu wrote:
> DIP74's function call protocol for RCOs has the caller insert opAddRef
> for each RCO passed by value. Then the callee has the responsibility to
> call opRelease (or defer that to another entity). This choice of
> protocol mimics the constructor/destructor protocol and probably shows
> our C++ bias.
>
> However, ARC does not do that. Instead, it implicitly assumes the callee
> is a borrower of the reference. Only if the callee wants to copy the
> parameter to a member or a global (i.e. save it beyond the duration of
> the call), a new call to retain() (= opAddRef) is inserted. That way,
> functions that only need to look at the object but not store it incur no
> reference call overhead.
>
> So I was thinking of changing DIP74 as follows:
>
> * Caller does NOT insert an opAddRef for byval RCOs
>
> * Callee does NOT insert an opRelease for its byval RCO parameters
>
> It seems everything will just work with this change (including all move
> scenarios), but it is simple enough to make me worry I'm missing
> something. Thoughts?

I recall saying something like this, and someone came up with a reason 
why you still have to add the calls. I'll see if I can dig it up.

OK, I found the offending issue. It's when you pass a parameter, the 
only reference holding onto it may be also passed as well. Something like:

void foo(C c, C2 c2)
{
    c2.c = null; // this destroys 'c' unless you opAddRef it before passing
    c.someFunc(); // crash
}

void main()
{
C c = new C; // ref counted class
C2 c2 = new C2; // another ref counted class
c2.c = c;
foo(c, c2);
}

How does the compiler know in this case that it *does* have to opAddRef 
c before calling? Maybe your ARC expert can explain how that works.

BTW, Michel Fortin is who pointed this out.

-Steve


More information about the Digitalmars-d mailing list