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

Reply via email to