[gclist] Finalization and object orientation.

David Chase chase@world.std.com
Mon, 31 Mar 1997 09:48:32 -0500


At 07:21 AM 3/31/97 -0600, Charles Fiterman wrote:
>Great tell me about this method topoSort() does it detect cycles. Where
>do I get source.

Well, this explains many things.  The most irritating thing about
your proposals for finalization is that you seem unconcerned by the
problems pointed out by intelligent, experienced people, as if they
were merely a bunch of lazy whiners.  topoSort is topological sort,
and yes, it detects cycles.  Any introductory computer science text
on algorithms ought to explain it.

There's big problems with your position that finalization ought
to be certain, timely, and "simply another method".  Certain and
timely finalization also requires certain and timely collection
of all garbage.  This is difficult to guarantee; it is essentially
impossible without a cooperating compiler.  Your proposal that
finalization is also "just another state change" also conflicts
somewhat with these requirements, because this (to me) seems to 
conflict with the goal of timely finalization.  The reason of this
conflict is the possibility of "resurrection" -- if a finalizer
places an object, or a referenced object, within some data structure
referenceable from live memory, it potentially converts almost-garbage
into non-garbage.  If finalizer are run in random order (good for
timely finalization) then the resurrected object may or may not have
been finalized.  Previously, only non-finalized objects could have
been seen by the mutator, but now it can see finalized objects
and non-finalized objects.  This also breaks encapsulation, because
if I use a Foo in my data structure, if I choose to resurrect that
Foo, I had better know whether a finalized Foo can be used for anything
at all.

Even if I run finalizers in topological order (i.e., starting at truly
unreferenced garbage, then objects only referenced by unreferenced
garbage, etc.) I still don't know if the Foo that I resurrect
WILL have its finalizer run, or not.  If, in addition to running finalizers
in topological order, I also check to see if an object is still garbage
before running its finalizer, I avoid this problem, but now I have
put you back into the billion dollars in a billion years case; each
GC can only finalize the completely unreferenced objects (this can be
avoided by using a write barrier to detect finalizer writes into live
memory, but this can interfere with your mutator, since it may wish
to write into live memory, and again demands a highly engineered GC
system).

The alternative I see is to decide that you have just carried a good
idea to a ridiculous extreme -- finalizers ought to be employed for
a FINAL state change, finalized objects ought to be in some sense second
class, and finalizers should not resurrect garbage.  This is another
set of consistent positions, that actually make it more possible to
provide timely finalization (run the finalizers in any order, don't
worry about resurrection), and that is consistent with how finalizers
are specified in Java (the fact that they can be run automatically only
once is a strong clue that you ought not resurrect objects, because
the resurrected objects will be in a weird state.  Just because the
language definition specifies how a corner case will behave, does not
mean that it is a good idea to program using that corner case).

David Chase