[gclist] Destructor FAQ
boehm.PARC@xerox.com
boehm.PARC@xerox.com
Fri, 15 Mar 1996 10:17:08 PST
"In Lisp, the language doesn't prevent you from ever seeing NILs, but it
gives you tools for checking whether something is NIL in a well-defined
manner. Now NIL is fairly useless -- you can't write data to it and so
forth. But it's not *totally* useless (you can check whether something
is NIL), and anyway the important thing is that the semantics of NIL is
well-defined."
I think that's an interesting analogy. Finalization code in a language without
constraints on finalization ordering essentially has to be prepared to see NIL
anyplace. And that unfortunately doesn't just mean code inside finalization
procedures; it means code inside the procedures they call.
And it's a little worse than that, since the language doesn't require that
finalized objects be clearly recognizable like NIL; the program has to ensure
that.
Perhaps I should restate my previous request to keep the terminology straight:
Let's not dicuss "synchronous" destructors as in conventional C++. I've never
missed them in a garbage collected language. Since they occur at well-defined
points, they are essentially syntactic sugar for a procedure call I could make
explicitly. And they don't have all that much to do with garbage collection
(except that they are one of several hooks which together can be used to
implement slow but portable GC).
The interesting issue is what happens when the garbage collector discovers that
an object with a clean-up action has been dropped. That's something the
programmer can't handle without language or library support, and thus needs to
be addressed. (Integration of a synchronous mechanism with this mechanism is
an issue, but I think it's very language specific.)
"Can anybody think of a realistic example in which a cyclic structure has
some pieces with finalization? I can't right now."
The cycles are usually accidental and some of the links are irrelevant to
finalization. The canonical example (due to Chris Jacobi) is some object P
with a finalizer (e.g. some window system resource) that also happens to have
an attached property list that can store arbitrary (name, value) pairs. In a
large system, you might easily get a path from one of the values back to P.
And no individual module has enough information to determine that there might
be such a path.
Of course this is easily fixable, since the finalizer presumably doesn't need
the property list. You could split P into P' and R, with P' pointing to R, but
not the other way around, and R containing the information needed for
finalization. P' would contain the property list pointer. All outside
references would be to P', so the cycle no longer involves the finalizable
object. Or you can do the same thing with post-mortem finalization. If you
don't want to split the object, you can get the same effect by adding
primitives similar to those in our collector. Or ...
Hans
Standard disclaimer ...