Path: utzoo!utgpu!news-server.csri.toronto.edu!cs.utexas.edu!tut.cis.ohio-state.edu!LUCID.COM!jonl From: jonl@LUCID.COM (Jon L White) Newsgroups: comp.lang.clos Subject: destructors in CLOS? Message-ID: <9012200651.AA00980@caligula> Date: 20 Dec 90 06:51:08 GMT References: Sender: welch@tut.cis.ohio-state.edu Distribution: inet Organization: CommonLoops Lines: 127 re: I would like to define a method that gets called when a CLOS instance gets garbage collected, sort of like a destructor method in c++. Can I do this in CLOS? How? This question has been asked several times in the past year, the most recent two instances of which are Eero Simoncelli's query to this very list last summer, and Roman Cunis's question raised at the CLOS workshop during ECOOP/OOPSLA '90 last October. Here is Eero's query, and the only reply to it that I ever saw: Date: Wed, 18 Jul 90 16:46:49 PDT From: eero@newton.arc.nasa.gov (Eero Simoncelli) To: CommonLoops.PA@Xerox.COM Subject: Any plans for a finalize-instance method? Are there any plans to incorporate a "finalize-instance" method (complementing the initialize-instance method) in the CLOS spec? This method would be called after the instance was orphaned (i.e. all references destroyed), but before it was garbage-collected. Obviously, this requires an implementation-dependent hook into the garbage-collection process. This would allow cleanup of allocated foreign or system structures, static data resources, etc. Eero. Date: Wed, 18 Jul 90 20:01:39 PDT From: smh@franz.com (Steve Haflich) To: eero@newton.arc.nasa.gov . . . Franz's 4.0 release will provide object finalization, as do some other implementations, but I doubt X3J13 would agree to require it in the language spec on two grounds: First, . . . At the CLOS workshop, I mentioned that Lucid has developed a finalization technique independent of CLOS and that it would likely be in the next release (I have had experimental versions running for some time now, but I'm not authorized to make product announcements; the current released product, Lucid 4.0, reached design closure last Spring, and doesn't have this code in it.) Chris Richardson, from Franz Inc., also mentioned that Franz had been working on a finalization technique that would be released in their upcoming 4.0 version, which he said would be due out in January or February 1991. However, you need to compare what "finalization" is likely to mean in implementations that are not doing true "garbage" collection. At the very least, it will not likely be as simple as merely placing a method on FINALIZE-INSTANCE -- probably it will require some individual registration of the objects to be finalized, which could be done on a per-class basis by an initialization(!) method. In practice, it may feel as simple as a defmethod, but there are couple of differences that can be observed by judicious test cases. This is why I said that "finalization" will be independent of CLOS. But of course CLOS objects will be finalizable just like any other stored-memory object will be; Steve Haflich, in his reply to Eero above, also stressed this point. Also, you should be aware of the slight difference between "destructor" and "finalization"; the former is the code that actually "disassembles" some no-longer useful object, whereas the latter is the process of identifying which objects that the "Garbage Collection" process, or the "Garbage Abandonment" process, should tickle upon when such an object is discovered to be abandoned. In the current C++ world, there is no automatic memory management, so the end-user code itself must invoke the destructor. Furthermore, the "destructor" code might typically try to recycle the space consumed by the object being "destroyed" (such as by placing it back in a pool of available such objects); but in Lisp, of course, you typically wouldn't try to thread the piece of garbage back into a live pool, but would rather let the next cycle of GC pick it up (on the other hand, you might do it anyhow!) It is worth noting that some of the participants in the Garbage Collection Workshop at ECOOP/OOPSLA '90 (myself included) are currently actively disussing how garbage collection *might* be added to C++. There is definitely some very serious concern by the more C-oriented folks in that group that "finalization" (as opposed to destructors) can never be a precise process. First, in the worst case scenario, the C++ world might not be able to tolerate "complete GC" -- that is, they may be reduced to coexisting with so-called "conservative" garbage collectors, whose contract is merely that they will (1) try hard to collect some garbage, (2) and never collect any living structures, (3) but leave open some reasonable paths in which particular pieces of garbage will never be collected, even though the user's program has dropped all pointers to them. So it is possible that the requirement for precise finalization may rule out some otherwise important GC techniques. This concern about the ability to prove that something is in fact garbage can even spill over into the Lisp world. For example, an optimizing Lisp compiler will probably use temporary registers in such a way that a pointer may appear to be "alive" even after the user's code has just smashed out the last copy of it in his own data structures. This seems to be a fact of "life in the big city", both in the Lisp world and in the C world. It may not be possible to reclaim a dead object until you exit from the last function frame that was referencing it. Finally, the question arises of just how urgent the demand to "finalize" a given object must be. How many seconds after dropping the last pointer to the object are you willing to wait until the destructor code is executed? In Interlisp-D (and presumably in the Common Lisp product that came out of it in latter years, now marketed by a company called Venue), this was essentially not a problem, because it used a reference-counting GC; and usually within a very short time of the reference count being decremented to zero, there would be an incremental collection that would run the associated destructor code. That is, you wouldn't have to wait until consing activity crossed some threshold and triggered a GC, or until you explicitly called GC from user code; the reference-counting and incremental triggering was sufficient. [Yea, Interlisp-D had a form of finalization back in the early 1980's, and I even put it into PDP10 MacLisp in the early 1970's for just the reasons that Eero mentioned above. But what neither system offered was a mechanism for the end-user to hook his own datatypes up for finalization. These earlier versions were specifically hooked only to certain system datatypes that connected to "system" data-structures. Oh yes, I recall the lacuna in the earlier versions of Interlisp-D where the incremental GC didn't scavenge everything available; we would have to do something like (RPTQ 20 (GC)) in order to assure that the last bit of garbage got "licked up". But I'm fairly certain that that gap was later plugged.] -- JonL --