Condition Style Guide #
hacking, June 3rd 2009
I don't claim this to be authoritative, but I'd be very interested in hearing any opposing views. So: a quick style guide for using the Common Lisp condition system — I'm eliding restarts for now, though.
Signalling Conditions
Use #'ERROR to signal conditions inheriting from SERIOUS-CONDITION. This includes all subclasses or ERROR. SERIOUS-CONDITION is a convention that means "this will land you in the debugger if not handled", which is what #'ERROR ensures.
- Inherit from ERROR if unwinding from the error leaves the system in a consistent state. Subclasses of ERROR mean "oops, we have a problem, but it's OK to unwind."
- Inherit from SERIOUS-CONDITION, not ERROR, if the system is messed up somehow, and/or requires either human intervention or special knowledge about the situation to resolve: SERIOUS-CONDITIONs that are not ERRORs mean that "something is deeply wrong and you should know what you are doing if you are going to resolve this."
Use #'WARN to signal conditions inheriting from WARNING. This includes all subclasses of STYLE-WARNING. WARNING is a convention that means "this will print out a warning if not muffled, and you can muffle this with the MUFFLE-WARNING restart", which is what #'WARN ensures.
- Inherit from STYLE-WARNING if muffling the warning should be fine pretty much whenever.
- Inherit from WARNING, not STYLE-WARNING, if muffling the warning is OK only if the muffler knows how to deal with the specific warning: otherwise someone should be made aware of the situation, which is what warnings are for.
Otherwise use #'SIGNAL, and don't expect others to handle your conditions unless you document them as part of your API.
Handling Conditions
Learn the difference between HANDLER-BIND and HANDLER-CASE. Short version: HANDLER-CASE always unwinds, with HANDLER-BIND you can eg. log the condition without handling it, or decide whether to unwind or not after inspecting the condition in more detail.
Don't handle arbitrary conditions: a lower layer using #'SIGNAL as a communication mechanism will break if you do that.
Don't muffle arbitary WARNINGs that are not STYLE-WARNINGS. A full warning can still be muffled, but only if it's one you know to be harmless in your case. Otherwise, a full warning should either result in a fail-stop, or logging the condition somewhere — depending on the kind of application you are developing.
Don't handle arbitary SERIOUS-CONDITIONs that are not ERRORs: if you cannot pop up a debugger and don't know exactly how to deal with this specific condition, the right answer is to crash — of course preferably with an error message, but don't expect that to work properly: maybe the serious condition was about corruption in the IO system...
If you just want to ensure the application doesn't enter the debugger, bind *DEBUGGER-HOOK* appropriately — but be aware that #'BREAK circumvents *DEBUGGER-HOOK*: if that's a danger, refer to the documentation of the implementation you are using — most provide a way to hook into #'BREAK.
Happy hacking.