On Fri, 18 Apr 2014 01:53:00 -0400, Walter Bright
<newshou...@digitalmars.com> wrote:
On 4/17/2014 6:58 PM, Michel Fortin wrote:
Auto-nulling weak references are perfectly memory-safe. In Objective-C
you use
the __weak pointer modifier for that. If you don't want it to be
auto-nulling,
use __unsafe_unretained instead to get a raw pointer. In general, seeing
__unsafe_unretained in the code is a red flag however. You'd better
know what
you're doing.
If you could transpose the concept to D, __weak would be allowed in
@safe
functions while __unsafe_unretained would not. And thus memory-safety
is preserved.
I recall our email discussion about implementing ARC in D that we
couldn't even avoid an inc/dec for the 'this' when calling member
functions. So I don't see how inc/dec can be elided in sufficient
numbers to make ARC performant and unbloated.
The important thing to recognize is that it's the *caller* that
increments/decrements. This means you can elide calls to an object where
you already have a guarantee of its reference count being high enough.
I looked up the example you referred to, it was this:
class R : RefCounted
{
int _x;
int readx() { return _x; }
}
int main()
{
R r = new R;
return r.readx();
}
According to 12. there is no refcounting going on when calling or
executing readx. Ok, now what happens here:
class R : RefCounted
{
int _x;
int readx(C c)
{
c.r = null; // "standard" rc deletes r here
return _x; // reads garbage
}
}
class C
{
R r;
}
int main()
{
C c = new C;
c.r = new R;
return c.r.readx(c);
}
This reads garbage or crashes if there is no reference counting going on
when calling readx.
So essentially, main needs to increment c.r's ref count. But not c's,
because it already knows that it owns one of c's reference counts. R.readx
does NOT need to increment its own reference count.
I think the distinction is important.
Also, consider if R is a final class, it can inline readx and can possibly
defer incrementing the ref count for later, or cache _x before setting c.r
to null (probably the better option).
Opportunities for elision are not as hopeless as you make it sound. The
compiler has a lot of information.
The rules should be:
1. when compiling a function, you can assume parameters have at least one
reference count increment that will not go away.
2. When passing an object into a function, ensure #1 is true for that
function.
Given D's type system of knowing when variables are shared (and if we
implement thread-local destruction of unshared data), we have a lot more
power even than Objective-C to make better decisions on ref counting.
Of course, you can always *manually* elide these things, but then if you
make a mistake, then you've got a leak and memory corruption.
Manual eliding should be reserved for extreme optimization cases. It's
similar to cast. Apple considers it dangerous enough to statically
disallow it for ARC code.
-Steve