Finalizers, GC, greenlets and the grue
I intend to implement greenlets, also called coroutines, in my language. Though greenlets have a feature that seems to be quite of a twist:
If all the references to a greenlet object go away (including the references from the parent attribute of other greenlets), then there is no way to ever switch back to this greenlet. In this case, a GreenletExit exception is generated into the greenlet. This is the only case where a greenlet receives the execution asynchronously. This gives try:finally: blocks a chance to clean up resources held by the greenlet. This feature also enables a programming style in which greenlets are infinite loops waiting for data and processing it. Such loops are automatically interrupted when the last reference to the greenlet goes away.
Greenlets represents separate stacks, which you can switch between. It allows you to suspend one task during I/O and have the same thread run different tasks until the I/O call finishes. In short, it lets you do co-operative scheduling inside your process. Interactive programs tend to be full of small things that each need to happen at the same time, yet none of the tasks is not huge enough to justify the cost of a hardware thread.
finally -statement is a mechanism to clean up and release resources did the code fail or not. If the greenlet becomes unreachable and is collected , the gc in cpython throws an exception into the greenlet and runs through the finalizers, during a gc cycle! My greenlet isn't an atomic unit, but several records in the heap, each which might end up being collected at a different time. To run the finalizer, I would have to collect a small greenlet handle, before I get rid of the rest, because one needs all those records to run the finalizers.
It's been argued before that things such as file handle management shouldn't rely to garbage collection, because the finalizers might never run if there is no need to collect garbage. Garbage collection presents an illusion of infinite space to put your things in.
Garbage collection alone eliminates the memory leaks only. To have something such as weak links, that can lose their reference, we need to assume there's a grue, which can eat those unreachable objects and set the weak link null. The same mechanism can be used to implement finalizers, but actually that's not needed.
You can use the weak links to implement finalizers, without having to run user code asynchronously inside a gc cycle. Associate the weak link with a finalizer, put it into a list. Make sure the finalizer doesn't point to the collectible object, because otherwise it will be reachable. Next you can run through the list in regular periods, calling every finalizer with a weak link cut out.
I think I'll provide the
try:finally: -equivalent, but I hope people won't expect the finally -block to run if the greenlet becomes unreachable. In the end the grue doesn't seem to contribute much to the programming experience, I haven't seen a single situation where I'd have found weak links or finalizers useful. You still need to take care of your resources even if the memory is managed.