On Wednesday, 26 July 2017 at 02:58:00 UTC, Mike Parker wrote:
Regarding the issue with `destroy` not being @nogc, I my
understanding is it comes down to `rt_finalize` not being
@nogc. I haven't dug too deeply into the discussions around it,
but I'm wondering if it's possible to separate the concept of
destruction from finalization in the implementation?
Possible, yes, and I agree that separating destruction
(deterministic end of object lifetime) and finalization (GC
collection caused end of object lifetime) for classes is
something we should do.
Externally, we can do it with the existing language:
class {
~this() {} // Finalizer
~this @nogc {} // Destructor
}
As class destructors (in contrast to class finalizers) are then
called exclusively in a deterministic fashion, there's no reason
to forbid them from allocating using the GC, so I don't think
using the @nogc attribute would be appropriate; I would much
rather see another attribute in the likes of @disable, e.g.
@deterministic, so
---
~this() {} // Finalizer
~this() @nogc {} // Finalizer
~this @deterministic {} // Destructor
~this @nogc @deterministic {} // Destructor
}
---
Internally, the runtime will treat each differently. an
rt_destruct would call all every __dtor in a hierarchy
As long as finalizers are then not part of __dtor.
and rt_finalize would be changed to call every __finalizer (a
new addition) in a hierarchy.
When cleaning up, the GC will ensure that all destructors are
run where they exist, followed by all finalizers.
Having the GC directly call destructors defeats the point of
separating them from finalizers in the first place: If a
destructor should be run on GC finalication, the finalizer must
manually call the destructor (using e.g. `destroy`).
The GC must *never* call destructors automatically after
splitting off finalizers, because that would turn destructors
back into finalizers.
And destroy would be changed to call rt_destruct instead of
rt_finalize.
Yes, that would then be the correct behaviour for `destroy`.