On Wednesday, 28 June 2017 at 00:05:20 UTC, Guillaume Piolat
wrote:
On Tuesday, 27 June 2017 at 23:54:50 UTC, Moritz Maxeiner wrote:
- Replace calls by the GC to `~this` with calls to `finalize`
(or invent some cool other shortened name for the latter)
My point is that in such a "finalize()" function the only sane
things to do is to crash if the resource wasn't freed already.
Why so?
[...]
Not every class can't be finalized, so it might make sense for
finalization to remain an available option.
What I think reasonable is treating destruction and finalization
as two distinct things. This could look like the following:
---
// Does not refer to other GC memory, can be finalized
class File
{
private:
int fd;
public:
this() { fd = open(...); }
~this() { close(fd); }
// If the GC collects a File object that hasn't been
destroyed yet, it will call this finalizer,
// which *manually* calls the destructor (because it's safe
to do so in this case)
// A File object can still be manually `destroy`ed
beforehand, in which case this particular finalizer is still
safe, since an object won't be destroyed twice
finalize() { destroy(this); }
// Or maybe prettier: alias finalize = ~this;
}
class Foo
{
private:
File f;
public:
this() { f = new File(); }
// Make the process crash on finalization of an undestroyed
Foo object
@disable finalize();
}
---
- Reserve `~this` for being called by deterministic lifetime
management (std.experimental.allocator.dispose,
object.destroy, RefCounted, Unique, etc.)
That's precisely what the GC-proof-resource-class allows, by
preventing defective, non-composable usages of ~this.
The GC proof resource class idiom is a necessary hack, but it
*is* a hack with its own limitations (e.g. depending on Error
being catchable).