On Tuesday, 27 June 2017 at 13:11:10 UTC, Steven Schveighoffer
wrote:
But I would use a close method, and not destroy(obj). The
reason is because often times, you have wrapper types around
your socket type, and just one extra level of indirection means
the destructor cannot be used to clean up the socket (you are
not allowed to access GC-allocated resources in a destructor).
All destructor restrictions do not apply when it's not called by
the GC.
There really are two categories of destructors: called by the GC
and called deterministically. Their usage should not overlap.
My reasoning went with the following:
1 - "I should have close() methods so that I don't rely on the
GC, and the GC is calling ~this from the wrong thread etc, not
everything can be released in this context (eg: OpenGL objects
should be released from one thread only). Close methods will call
close methods of "owned" objects."
2 - "Uh, oh. Refcounted and Unique and Scoped all use .destroy,
so destructors should call close() methods. To avoid double
release, close should handle being called several times. The GC
will close what I forgot!"
3 - "Actually there is no order of destruction when called by the
GC. So I can't release owned objects when called by the GC.
Better do nothing when close() is called by the GC, let's detect
this.
4 - close() is now identical with ~this (at least for classes).
Let's remove the close() method. Crash when a resource is freed
by the GC.
That's how the GC-proof resource class came to existence, after
many destruction bugs, and it let's you use the GC as a detector
for non-deterministic destruction. I miss it in @nogc :)
https://p0nce.github.io/d-idioms/#GC-proof-resource-class
Remember years ago when Alexandrescu suggested the GC shouldn't
call heap destructors? That's what we get for having said no at
the time.