On Friday, 25 May 2012 at 11:23:40 UTC, Jacob Carlborg wrote:
On 2012-05-25 11:02, foobar wrote:

It makes the call order deterministic like in C++.

e.g.
class Foo {}

struct A {
resource r;
~this() { release(r); }
}

struct B {
A* a;
Foo foo;
~this() { delete a; } // [1]
}

I though we were talking about classes holding structs:

class B {
    A* a;
    Foo foo;
    ~this() { delete a; }
}

In this case you don't know when/if the destructor of B is called. It doesn't help to wrap it in a struct, you could just have put it directly in A. Is that correct?


No. see below.

Lets look at point [1]:
The "foo" instance is "managed" by the GC since the only resource it holds is memory. The "a" member wraps some "non-managed" resource (e.g. file descriptor) and in this model is still valid, thus allows me to
deterministically dispose of it as in c++.

Ok, but if B is a class?

This can be simply checked at compile-time - you can only reference non class instance members in the destructor, so adding a "delete foo;"
statement at point [1] simply won't compile.

If you have a pointer to a struct you don't know how it was created. It's possible it's been created with "new", which means the garbage collector needs to delete it.

let's say we add two classes:
class FooA {
  A a;
}
class FooPA {
  A* pa;
}

For the first case, both the class and the struct share the same lifetime thus when an instance of FooA is GC-ed, the GC would call A's d-tor and allow it to do what-ever (self) cleaning it requires. This means the d-tor will always be called.

For the second case, The GC will only scan "pa" to find inner class instances but will *not* handle the struct value itself. In order to clean what "pa" points to, you need to explicitly call the destructor yourself. One way to do this would be to register a callback with the GC to get notified when an instance of FooPA is collected and inside the callback function maintain a reference-counter. This also means that if you allocate a struct value on the heap via "new" you are responsible to call delete _yourself_ and the gc will not call it for you. I think that loosing this small convenience is worth it - we gay more orthogonal semantics that are easier to reason about.


Reply via email to