3 ms·
Restarts are nice. The thing is, though, is that restarts are relatively easy to add to any language that has well-supported structures for non-local control f
by phs2501 11y ago
Restarts are nice.
The thing is, though, is that restarts are relatively easy to add to any language that has well-supported structures for non-local control flow; they're just a protocol, after all. That's really what Common Lisp has which most other languages lack. Common Lisp (very intelligently, IMHO) did not conflate error handling with non-local control flow; they are different concepts and deserve to be treated independently.
Specifically, the lexcal scoping of BLOCK and TAGBODY labels and the fact that RETURN-FROM and GO will unwind the stack if necessary to get to the target label make creating something like HANDLER-BIND/RESTART-BIND relatively easy. (There is also of course THROW and CATCH [which don't really have anything to do with error handling in CL, they're just structures for dynamically-scoped stack unwinding], but I've generally found the need to create explicit labels for those less elegant than using lexical scoping. You can always use a closure if you need to store the lexicaly-bound state to be used somewhere else, and the reverse is not as easy...)
You obviously also need UNWIND-PROTECT to keep things safe when the stack unwinds, but most languages successfully manage to get that with something like try-finally (or RAII in C++'s case, even if I find it clumsy sometimes).
- jsnell 11y agoYou can implement the CL condition system in pretty much any language, but it's not going to be useful. The value of the condition system is strongly tied to it being used consistently everywhere in the language and in the libraries.
- phs2501 11y agoFair point. What I was attempting to convey is that the reason I think the CL condition system works so well is that at its core it doesn't attempt to manage control flow directly; i.e. neither HANDLER-BIND nor RESTART-BIND unwind the stack on their own, and even ERROR only gets its behavior by falling back to INVOKE-DEBUGGER if unhandled. Because CL has good tools for doing non-local control flow that aren't bound up in its condition/exception system it winds up strictly more expressive (IMHO) than languages that conflate these. What I've noticed from languages that have traditional try/catch exception handling (especially when that's the only non-local control flow available) is that the mechanism of error handling is seen as DEEP MAGIC by their users. If you separate it out into non-local control flow and a protocol for communicating exception handlers as CL does, the "magical" properties go away since it can be seen how the condition system could be implemented. Or at least that's how it worked for me.