
Adding finalizers to arbitrary objects was useful for the memo table application we had in mind when weak pointers were introduced, but for all the other applications I've come across since then, we really want to add finalizers to objects whose lifetimes are under programmer control. Notice how ForeignPtrs attach the finalizer carefully to the MutVar# inside the ForeignPtr, not the ForeignPtr itself.
One application that was effectively killed by GHC's approach to finalizers was GHood (I lost interest when it became apparent that GHC was moving away from giving any kinds of guarantees about finalizers). The idea was that, just as unsafePerformIO gives us a way to instrument the evaluator, so finalizers could have given us a way to instrument garbage collection. Then GHood could not only have shown when which parts of which structure are first observed (how and when structures get unfolded) but also (roughly) when which parts of which structure become unreachable (how and when structures disappear again). That would have made a very nice tool. But it would have needed finalizers on arbitrary objects that are actually guaranteed to be run, preferably promptly, but not early. Given the application, I would have considered wrapping/annotating those objects in some transparent way, not visible to the original program, but forcing the memory manager to keep track of that object even if that means worse code. Only that there are no guarantees whatsoever on these finalizers anymore (there were some back then, but it emerged that they weren't backed up by the implementation). Which also hurts other, table-like, applications: I have an application where I need to keep track of synchronous communication channels, basically: advance each live channel at every step. Now, I would like to attach finalizers to the channels, so that when there are no more threads having references to a channel, the channel gets removed from the tracking table. But without finalizer guarantees, there is no guarantee that the table will not simply keep accumulating more and more of those dynamically created channels.. I, for one, would like to have good support for "adding finalizers to arbitrary objects with useful run guarantees". Actually, it is a bit hard to understand what finalizers without any guarantees (System.Mem.Weak) are supposed to achieve? Claus