Thu, 10 Apr 1997 15:30:04 -0400
[Usefulness of finalizers for files backing "ropes" in an editor.]
I don't think we actually disagree. I'm saying thatt, *in general*, using finalizers to (attempt to) implement an abstraction on
top of files which hides errors, lack of file descriptors, etc., will fail.
You've described a specialized example, ropes, which open files read-only, so
don't have to deal with asynchronous errors, can afford to close a file to
return the descriptor in times of need, then later open it again and position
back to where they were, etc. (Not that finalizers would help you implement the
I don't disagree that finalizers are a useful tool. But they are a tool that
should be used relatively rarely, in well-defined situations. Problems arise
when people try to elevate finalizers to a central role. Perhaps a good analogy
is to exception handling. It's a wonderful program structuring tool, and works
extremely well in its intended role as a way of dealing with rare conditions.
It's certainly possible to use it as a basic program design technique, analogous
perhaps to failure in SNOBOL4 and Icon. You can come up with some really
elegant expressions of algorithms that way. But the resulting code will run
like a dog, since exception handling is slow in just about every implementation.
There's even an analogue to this at a lower level. One can write some very
elegant numerical algorithms that rely on IEEE FP arithmetic, and in particular
on its handling of various exceptional conditions. Bad idea. Real hardware
rarely implements the full model; exceptional conditions are punted to software,
and will be very slow. Fine for the typical, intended uses; killers when they
end up in the main line of execution.
The problem with finalizers isn't *exactly* like the problem with exceptions.
It's not that finalizers are, or have to be, inefficient. Rather, it's that the
actual abstract properties they can safely be assumed to have are pretty
limited. Safe? Sure? Prompt? Which do you want? What will you pay for them?
As they say, when all you have is a hammer, everything looks like a nail. The
typical modern programming language provides all sorts of structuring tools
appropriate to different uses. Pick any one detailed semantics for finalizers -
with weak guarantees and high performance, or strong guarantees and a great deal
of overhead - and what you get isn't a hammer; it's a single hex key, say.
Great at what it does; you *could* use it as a punch, a pry, perhaps even as a
hammer - but it's not really *good* at any of those things.
PS: The old, dead pre-X VMS window system, VWS, used an I/O channle *per
window*. This had all sorts of nice properties in the interface you ended up
with - after all, a window *is* a kind of virtualized I/O device, isn't it - but
could be used on VMS only because the number of I/O channels a process could
open could cheaply be set very large - typically in the thousands, for systems
running VWS. Such an interface would never have flown on Unix, which in those
days typically allowed 20 file descriptors per process, and today usually allows
on the order of 64 by default, and perhaps 1024 maximum. So, yes, file
descriptors are *still* precious resources, in that you have to think about how
you are using them in the way we used to have to think about memory - but
generally no longer do. -- J