Tuesday, February 10, 2009

Finalizers Considered Questionable

If you glue C to a GC-ed language, you end up with the question what to do with structures passed from C. One way of handling them would be to add finalizers to objects in the GC-ed language. I am figuring out what others did. A post from Python-Dev.

Here's my $0.02.

I agree with the sentiments that use of finalizers
should be discouraged. They are extremely helpful
in cases like tempfile.TemporaryFileWrapper, so I
think that they should be supported. I do think that
the language should not promise a high level of service.

Some observations:

- I spent a little bit of time on the ANSI
Smalltalk committee, where I naively advocated
adding finalizers to the language. I was resoundingly
told no. :)

- Most of the Python objects I deal with these days
are persistent. Their lifetimes are a lot more complicated
that most Python objects. They get created once, but they
get loaded into and out of memory many times. In fact, they
can be in memory many times simultaneously. :) A couple
of years ago I realized that it only made sense to call
__init__ when an object was first created, not when it is
subsequently (re)loaded into memory. This led to a
change in Python pickling semantics and the deprecation
of the loathsome __getinitargs__ protocol. :)

For me, a similar case can be made against use of __del__
for persistent objects. For persistent objects, a __del__
method should only be used for cleaning up the most volatile
of resources. A persistent object __del__ should not perform
any semantically meaningful operations because __del__ has
no semantic meaning.

- Zope has a few uses of __del__. These are all for
non-persistent objects. Interesting, in grepping for __del__,
I found a lot of cases where __del__ was used and then commented
out. Finalizers seem to be the sort of thing that people
want initially and then get over.

I'm inclined to essentially keep the current rules and
simply not promise that __del__ will be able to run correctly.
That is, Python should call __del__ and ignore exceptions raised
(or provide some *optional* logging or other debugging facility).
There is no reason for __del__ to fail unless it depends on
cyclicly-related objects, which should be viewed as a design

OTOH, __del__ should never fail because module globals go away.
IMO, the current circular references involving module globals are
unnecessary, but that's a different topic. ;)


I think I agree with this: ... GC is about memory management, not resource management .... The gist: since you cannot, in general, rely on finalizers being called when needed, or in the right order, better to avoid them.

No comments:

Post a Comment