3 ms·
My last comment was only addressing your 'too easy to' part (which, per sibling comment, may not be as universal an appearance as I thought). However, fair que
by mst 2y ago
My last comment was only addressing your 'too easy to' part (which, per sibling comment, may not be as universal an appearance as I thought).
However, fair question.
My answer here is that I am also really rather fond of timely destruction - in the same way as a Rust value's Drop happens as soon as the value is no longer required, a refcounting GC can fire destructors/finalizers immediately.
That means that e.g. if code that's using an "external" resource (think file descriptor) throws an exception, the resource will automatically be released during the stack unwind rather than having to wait for the next GC pass.
It also means that you can (and I, in fact, do) have a transaction object that can emit a warning at a useful point if you let it go out of scope without calling commit or rollback on it.
You can absolutely get (close) equivalents to this with a mark and sweep GC language, go's 'defer' strikes me as something I could implement at the very least 90% of these patterns with, but it's still something you have to consciously implement.
What's trickier is e.g. if you have N objects in flight sharing a resource but want the resource to go away when all of those are done - in a non-refcounting language you either have to track the count yourself (i.e. effectively implementing a mini-refcounter) or again rely on GC to sweep it up soon enough not to be a problem.
So it's a trade-off between having to think about resource releases and having to think about breaking cycles, and I'm not at all arguing refcounting is -better- but I personally mostly find it just -different- and I'm definitely not convinced that getting used to it is (much) harder than getting used to the relevant dances to not temporarily leak file descriptors and similar.