[gclist] Guardians

Hans Boehm boehm@hoh.mti.sgi.com
Thu, 10 Apr 1997 11:10:22 -0700

On Apr 10,  9:53am, Jerry Leichter wrote:
> Using finalizers to close files is never going to work correctly, since the
> abstraction simply doesn't have any way to hide the details of file access.
> best, it can ignore those details - fine for simple-minded toy programs,
> for real systems.

This hasn't been my experience.  In at least some cases, the programs that rely
on completely explicit file management, though advertised as industrial
strength, tend to be the ones that break under stress.

I think nobody here would argue that files should only be closed by finalizers.
 Files should be closed explicitly, and errors handled suitably, whenever
that's convenient.  Most of Richard's examples typically fall into this
category.  Anytime it can be easily determined that a file will become
inaccessible at a certain program point, it should be closed explicitly.

I also would not rely on finalization to close files if you only have 20
descriptors available.  If the OS only gives you 20 file descriptors you will
often have to introduce a more plentiful notion of virtual file descriptors
anyway.  No modern UNIX version has such a restriction.  I presume modern
Windows versions don't either, though I haven't checked.

There are cases in which explicit file management is hard, and it makes sense
to rely on finalizers.  Here are 2 such cases I've run into.

1. The file is read lazily be a data structure which may be deeply embedded in
other data structures.  Cedar strings (ropes) supported treating a file as a
string, reading on demand.  I have built a a C package (cords in the GC
distribution) and a C++ package (rope.h, will hopefully be released shortly on
the SGI STL site) that also support this.  The file is read-only, so the close
is unlikely to fail.  If it does, you don't care (beyond perhaps wanting to
inform the user), since you already got the information you needed.  The "toy"
editor included in the cord package has been used repeatedly to look at files
that were too big for the "industrial strength" editors which performed
explicit file management, and tried to read the whole file into memory (swap
space, really).

2. Files that are accidentally dropped, typically as a result of other error
recovery actions.  These may really be program bugs.  Or the programmer have
made an engineering tradeoff, in deciding that it was not worth the extra code
and complexity to handle secondory failures during error recovery in the
optimal manner.

I also don't see why the finalizer necessarily has less information available:
 It can still have access to relevant global state.  If local state is likely
to be interesting, then it seems likely to me that the file could have been
explicitly closed.

In general, I still believe that finalizers are rarely needed.  But there are a
few cases in which you really can't get away without them.  The time spent on
this list discussing their interface is way out of proportion to their
significance.  I can easily live with Java finalizers or Guardians, in spite of
the fact that I don't agree with the interface design.


Hans-Juergen Boehm