On Friday, 6 March 2015 at 14:59:46 UTC, monarch_dodra wrote:
struct RCArray(E) {
E[] array;
int* count;
...
}
auto x = RCArray([E()]);
E* t = &x[0];
But taking that address is unsafe to begin with. Do arguably,
this isn't that big of a problem.
Taking the address is only really unsafe (in a non-RC'd type) if
you don't have a lifetime tracking system. As long as the
lifetime of the address taker is shorter than the address of the
takee, it's not inherently unsafe. Whether D will end up with
such a system is a different question.
But I still think there's value in having a separate RCData type,
because you can save one pointer per instance of RCArray. Right
now, if you take a slice of an RCArray, your working array might
not start at the same place as the reserved memory array.
Therefore you need to keep a pointer to the reserved memory in
addition to your active working array. If the counter and the
pointer to the original memory are in the same place, one pointer
will get you both.
I think the idea is worth exploring.
Your first dual reference issue seems much more problematic, as
there are always cases the compiler can't catch.
How so? If all we're talking about is RC'd types, the compiler
can catch everything. I think the greater concern is that the
workarounds will take a toll in runtime performance. I'll try to
illustrate:
void fun(ref RCStruct a, ref RCStruct b);
auto x = new RCStruct;
fun(x, x);
This wouldn't be safe. If fun() contained a line "a = new
RCStruct;", b will point to deleted memory for the rest of the
function. The normal way to protect this to make sure there's
another reference:
auto y = x;
fun(x,x);
This is actually safe, because y bumps the reference counter to 2
when initialized, which is enough to cover all possible
reassignments of x. The compiler could do this automatically. It
could detect that the parameter x aliases itself and create a
temporary copy of x. But it would mean the runtime performance
cost of the copy and postblit and destructor call. So D probably
can't invest in that strategy, since the programmer should have a
choice about it.
So it's not about it being impossible to deal with the safety
problems here, just that the runtime cost is too high.
But there are some ways out. If the given type has no postblit,
for example (or "opAddRef" for classes), there's no reason to
mark the operation unsafe, since you know it's not reference
counted. Also, const parameters are safe and won't be affected.