[Python-Dev] finalization again

bwarsaw@cnri.reston.va.us bwarsaw@cnri.reston.va.us
Fri, 10 Mar 2000 15:56:45 -0500 (EST)


>>>>> "GvR" == Guido van Rossum <guido@python.org> writes:

    >> Given sufficient resolution of your system
    >> clock, you should never have two objects with the same
    >> timestamp.

    GvR> Forget the clock -- just use a counter that is incremented on
    GvR> each allocation.

Good idea.

    GvR> Suppose I have a tree with parent and child links.  And
    GvR> suppose I have a rule that children need to be finalized
    GvR> before their parents (maybe they represent a Unix directory
    GvR> tree, where you must rm the files before you can rmdir the
    GvR> directory).  This suggests that we should choose LIFO: you
    GvR> must create the parents first (you have to create a directory
    GvR> before you can create files in it).  However, now we add
    GvR> operations to move nodes around in the tree.  Suddenly you
    GvR> can have a child that is older than its parent! Conclusion:
    GvR> the creation time is useless; the application logic and
    GvR> actual link relationships are needed.

One potential way to solve this is to provide an interface for
refreshing the counter; for discussion purposes, I'll call this
sys.gcrefresh(obj).  Throws a TypeError if obj isn't a finalizable
instance.  Otherwise, it sets the "timestamp" to the current counter
value and increments the counter.

Thus, in your example, when the child node is reparented, you
sys.gcrefresh(child) and now the parent is automatically older.  Of
course, what if the child has its own children?  You've now got an age
graph like this

    parent > child < grandchild

with the wrong age relationship between the parent and grandchild.  So
when you refresh, you've got to walk down the containment tree making
sure your grandkids are "younger" than yourself.  E.g.:

class Node:
    ...
    def __del__(self):
	...

    def reparent(self, node):
	self.parent = node
	self.refresh()

    def refresh(self):
	sys.gcrefresh(self)
	for c in self.children:
	    c.refresh()

The point to all this is that it gives explicit control of the
finalizable cycle reclamation order to the user, via a fairly easy to
understand, and manipulate mechanism.

twas-only-a-flesh-wound-but-waiting-for-the-next-stroke-ly y'rs,
-Barry