[gclist] Finalization and death notices

rog@vitanuova.com rog@vitanuova.com
Wed, 10 Oct 2001 14:13:09 +0100

no, Limbo (the language) provides no form of implicit object
finalisation at all.  it does however require every potentially cyclic
pointer to be labelled as such (i.e.  the compiler helps to ensure
that you know when objects will go away immediately and when they
might linger)

behind the scenes, at the implementation level (in C), synchronous
destructors are provided; Inferno (the OS) uses these to ensure that
some OS-level resources are freed when their corresponding Limbo
handles are freed.  the modules responsible are written carefully to
ensure that no locks are held when pointers are manipulated.

file descriptors and bitmaps (potentially on a remote display device)
are probably the two most important ways this is used.

interestingly, the former can actually be used to implement "death
notices" in Limbo (although the cost is one process and two file
descriptors for each object!).  Inferno provides unix-style pipes;
when one end is closed, a process reading at the other gets EOF.

although i've sometimes had a slight yearning for user-level
destructors in Limbo, i've always been able to get away quite easily
without them.

i think this is partly due to the design of the language, which
doesn't support inheritance.  this means that every object
encapsulates, and is directly responsible for, all the objects that it
uses to implement itself.  this has several knock-on effects:

	o the scope and interdependency of different modules tends to
	be narrow, i think mostly because the lack of inheritance
	means that each interface is built from scratch to express its
	operations in the nicest way possible, rather than trying to
	massage some existing interface to accomplish the same task.

	o the above means that objects are not passed around
	willy-nilly by the system masquerading as other object types;
	they are used by code that knows that kind of object, and the
	requirements of that object's API, which makes it much easier
	to conform to those requirements.

	o it also means that it's usually much easier to verify that
	object requirements are met, because they're used in a
	controlled way inside a module that cannot have its invariants
	suddenly changed by another module coming along and
	subclassing it.

the other reason why finalisers are rarely needed in Limbo under
Inferno is that Inferno provides another programming abstraction: the
namespace.  this acts as a kind of loose (and potentially cross
network) coupling between programs, and makes explicit provision for
knowing what clients are around, when they leave, etc, making it easy
to clean up resources appropriately.  it's a heavier weight
abstraction, but that just means that one must think in terms of more
substantial primitives, which is perhaps no bad thing.  (to borrow an
electronics analogy from Brad Cox, perhaps this is board-level
abstraction rather than chip-level abstraction...)

i'm sorry, i've rambled for too long, but i think my point comes down
to this:

the necessity for finalisers is a function of programming style as
much as anything else, and programming style is intimately related to
the primitives and combining operators provided by the
language/environment.  Limbo programs survive very happily without
implicit finalisers; i think Hans is probably right when he says that
they are occasionally essential under other languages.