Smart pointers instead of GC?
Adam D. Ruppe
destructionator at gmail.com
Tue Feb 4 19:58:36 PST 2014
On Wednesday, 5 February 2014 at 00:49:25 UTC, Walter Bright
wrote:
> What happens with this:
>
> T identity(T t) { return t; }
My previous post was with regard to nullability. This one is
about ownership.
The answer is the same: if you need this, use a template,
otherwise, you always deal with a specific type (if you are
allocating a new copy or need to store the reference somewhere
outside the owner's scope) or a borrowed type:
GC!Object obj;
static assert(typeof(identity(obj) == GC!Object);
and so on, you can test this today, D already has all these
options.
If you don't have a template, how do you approach this? Well,
this is really nothing new for one:
class Foo {}
Foo foo = new Foo();
Object obj = foo; // legal
Object identity(Object obj) { return obj; }
foo = identity(foo); // won't compile without an explicit cast
When you work with interfaces, some information is lost. That's a
pain sometimes, but it is a feature too - the function that works
on the interface doesn't need to care about anything else.
With class inheritance, we can address this with covariant
overrides.... but only of it is a member function (method).
So let's just accept that the free function loses data. You can't
get a container back from a range in the general case.
So, what about the method:
class Foo {
typeof(this) identity() { return this; }
}
What is typeof(this)? I'll tell you: Foo! Here's why:
*) The internal this pointer is never null, and thus never needs
to be nullable, so that's out of consideration (see my last
message)
*) The internal this pointer does *not* own its memory. Calling
"delete this;" is (I think) undefined behavior in D: the class
might exist on the stack, or be allocated with malloc, and
calling freeing the memory inside a method is likely to lead to a
crash when the invariant is called upon returning anyway!
Since the object does not own its own memory, it must always
assume this is a borrowed reference. Therefore:
* Escaping `this` is prohibited.
Foo globalFoo;
class Foo {
// illegal, escapes a reference to a borrowed reference
void storeThis() { globalFoo = this; }
}
Consider that this is wrong if the class is made with
std.conv.emplace (or the deprecated scope storage class) on a
stack buffer.
This is silently wrong today, it can leave a dangling reference.
(though since emplace is not @safe, we do have that protection
against such problems... though since we're talking about
avoiding the GC here, emplace is something we probably want
anyway)
* Returning this is always a borrowed pointer, unless you
explicitly make a copy.
class Foo {
Foo identity() { return this; }
}
GC!Foo foo = new Foo(); // owned by the Gc
Foo foo2 = foo.identity(); // borrowed reference, NOT GC!Foo
Therefore, we cannot escape it to a global that way either. If we
want that, we have to work with foo directly, bypassing
foo.identity.
A clone method would create a new owned thing, so it returns
something more specific:
class Foo {
GC!Foo clone() { auto foo = new GC; /* copy methods */ return
foo; }
}
A clone method might also be templated on an allocator, and can
thus change the return type as needed by the allocator. This
wouldn't be virtual... but it kinda has to be.
class Foo {
virtual GC!Foo clone() {...}
}
class Bar : Foo {
override RC!Foo clone() {...}
}
You wouldn't want that anyway, since if you called it through the
foo interface, you wouldn't know how to free it (does it need to
run a struct dtor? The GC? The caller needs to know.)
Gotta pick an allocation method in the base class if you want it
to work as a virtual function. So... yeah do that or use a
non-virtual template. You can make it work.
A clone method typically wouldn't even be inout anyway so meh.
* A class is responsible for its member references but not
itself. When the class' dtor is called, it needs to call member
struct dtors, but does not call free(this) - leave that to the
outside allcoator. This is already reality today (the GC calls
the dtor before releasing the memory).
More information about the Digitalmars-d
mailing list