A condition handler (sometimes exception handler) refers to a mechanism in some programming languages which allows the programmer to provide code to handle the occurrence of a exception or condition (terminology varies, but the substance does not).
When such an event happens (be it caused by some sort of hardware-detected issue, e.g. 'divide by zero', or purely software, e.g. 'unexpected end-of-file'), program execution is diverted to a condition handler for that specific condition, which is expected to deal with it.
In some modern languages (e.g. Ada and Java), conditions are intended to be used as control flow mechanisms in normal operation. In others (e.g. C++ and Common LISP), they are intended for use in dealing with unusual error situations.
In procedural languages (such as ALGOL and C - although neither one normally supports condition handlers), each procedure can set up one or more condition handlers on entry to an instance of the procedure. From then on, until that instance exits, any time that condition is signalled (in either that procedure, or any procedure it calls, and so on), execution jumps to that condition handler. Should an inferior procedure set up a condition handler for that same condition, the inferior procedure's handler will be invoked preferentially.
Condition handlers are usually provided with a number of ways to terminate their execution:
- they may (after repairing the condition that led to the signalling of the condition) resume operation at the place where the condition was signalled (although not all condition systems provide this option, since experience has shown it may not be useful);
- they may re-signal the condition to a higher-level handler for that same condition;
- they may signal a different condition;
- they may terminate the program (if the problem cannot be repaired).
Some languages use the term throw for raising an exception, and catch for the handler.
There are a number of approaches to implementing condition handlers.
One is to keep information about active condition handlers for any procedure's invocation in its stack frame in the call stack, so that handlers are automatically discarded when an invocation that set them up exits. When looking for a handler for a signalled condition, the condition system starts at the bottom of the call stack, and works its way upwards, looking for an active handler for that condition.
This approach has the drawback that is hard to provide 'resume' semantics, but it has the advantage that if a handler is inside a procedure, the handler can easily have access to that procedure's automatic variables. (It is hard to do both of these at the same time without a lot of work.)
Another possibility is to have a special stack on which condition handlers are listed, along with pointers to routines given the task of handling that condition. These must be un-stacked when the procedure invocation which set them up exits, which is extra overhead, but with this approach it is easier to provide 'resume' semantics.
In addition to the above, there are a variety of special operations associated with condition systems.
If no condition handler for a particular signalled condition is found in the call stack, the condition system may respond by signalling an 'unhandled condition' condition. Usually a handler for this condition is provided in the top-level procedure, to catch otherwise un-handled conditions.
An unwind protect is a special condition handler (named finally in some languages) which, if set up in any procedure instance on the call stack, if the call stack has to be unwound through that instance to get to a handler for a particular signalled condition, for any procedure invocation which is unwound which has a handler for "unwind protect", that handler is called 'on the way through'. This allows that instance to do any cleanup it needs to, before it is terminated by the condition system.
Condition handlers are usually more use in very large programs; in small programs it is easy to simply return special values, which indicate an error, through a small number of level of procedure call. In large systems, where it may be desired to handle a condition at a much higher level than where it happens, this would require a lot of special-case handling in many intervening procedures. Signalling a condition, on the other hand, can transfer control directly to the handler, without needing extra code in all the intervening procedures.
An example is a compiler using a recursive descent parser, which in turn calls a lexical analyzer. If the latter discovers an un-expected 'end of file', there can be an extremely large number of procedure invocations in between where that is discovered, and where it is desirable to handle it.