Dan Weinreb wrote a long blog post recently outlining what Common Lisp’s “Conditions (exceptions) are really about.” He argues, and I won’t disagree, that they provide a clean, even elegant, way to handle all the long tail of situations that arise when your trying to be fastidious about the contract for your functions. One of the things that used to be unique about Lisp was it’s elegant support for unwinding the stack when odd things forced you to abandon what ever your doing. It was a lot easier to see to it that the printer handle was relinquished, the file closed, the gate shut in Lisp than it was in Fortran or C. These days most languages are better about admitting that these things happen and something should be in the language to help.
Interestingly though the Common Lisp condition system remains a much more elegant thing than you find in other languages. I don’t really understand why. The condition system doesn’t just provide a way to unwind the stack, passing along an object instance to describe what ‘exceptional’ condition arose. It also allows the handler for these conditions to resolve them. In effect this provides an elegant way to implement call backs, i.e. that situation where a low level body of code needs to ask the higher, or later written, code how to resolve a problem. For example you can use the condition system to implement the classic call back scenario where a GUI widget wants to provide it’s users with the ability to do additional checking on user input.
There’s more, but what I really wanted to get off my chest (and that’s what a blog’s for eh?) is that I sometimes I like to muse about raising a condition is yet another example of how complex function calling really is. Back in the day we used to be able to figure out what function would implement a call site at link time. Later we got used to having dynamic linking do some of that, and it was common in memory constrained systems to load and flush code on the fly under the covers when in the function call. I’ve seen systems where you switched interpreters in the function call for performance and space trade off reasons. These days people are used to having a complex method dispatch that puzzles out what method will will take care of the request. The method dispatch is a messy beast when you allow new classes to be loaded. It was with some pleasure that I first read the mythical man month’s description of how some ornate linker came to be obsoleted; since at the time I was struggling with how loading compiled lisp files was an amazingly disruptive event; since it upset all your method tables.
Generally method dispatch is done by searches up stream in the acyclic directed graph of types. I.e. the behavior of the function is inherited from the class hierarchy. The class hierarchy is not the only hierarchy in most programs. For example there is almost always a containment hierarchy, i.e. the OK button is inside this dialog; or for example this file write is taking place inside the task of writing the log, inside the task of handling this web request.
At one point in my life I was quite enthusiastic about the idea of language designs that might allow these other hierarchies more respect. During that period I built a few class systems where behavior was inherited first from the containment hierarchy and only secondarily from the class hierarchy.
What I like about conditions is how when a condition is raised and the system goes off seeking a handler for that condition – it’s just another variant of method dispatch – and the call hierarchy is were we search for the handler. For me the fact that these calls often don’t return; or return in such unusual ways is part of what’s delightful about the condition system.