On Saturday, 29 August 2015 at 13:14:26 UTC, ponce wrote:
This makes GC-called destructors mostly useless for non-memory
resource release. IIRC Andrei suggested once that destructors
shouldn't be called at all by the GC, something that I agree
with.
As such, some of us started providing a
release()/dispose()/close() method, and have the destructor
call it to support both scoped ownership and manual release.
I'm not sure it is the best way to do things... In Python for
example we have a GC that calls the default destructor (__del__
method). As a consequence, if you need some resource to be freed
you have to do it explicitely by writting a close()/whatever()
method. But nobody's linking the destructor to it because of the
separation of concerns principle: we release what has to be
released and only that: freeing the object is the realm of the
GC. This mixed style is something I have yet to encounter in D
where it could be way more powerful than in Python: free what you
must, not what you can.
But that introduce accidentally correct design when the
destructor is called by GC, and avoids a leak. This is arguably
worse than the initial problem.
I'd like to see a concrete example of this, it seems I'm missing
something...
void ensureNotInGC(string resourceName) nothrow
{
debug
{
import core.exception;
try
{
import core.memory;
void* p = GC.malloc(1); // not ideal since it
allocates
return;
}
catch(InvalidMemoryOperationError e)
{
import core.stdc.stdio;
fprintf(stderr, "Error: clean-up of %s incorrectly
depends on destructors called by the GC.\n", resourceName.ptr);
assert(false); // crash
}
}
}
--------------
Looks ugly? Yes, but it makes the GC acts as a cheap leak
detector, giving accurate messages for still opened resources.
As I said before, I'm not sure preventing the GC from doing its
collection job is a good idea, but I find the concept of having
such a leak detector really interesting!