CSE 341 -- Exception Handling

An exception handler provides another control structure, for dealing with errors or exceptional cases.

Definitions (from the Ada manual): Exception An exception is an event that causes suspension of normal program execution. Bring an exception to attention is called raising the exception. An exception handler is a piece of program text specifying a response to the exception. Execution of such a program text is called handling the exception.

In Ada, users can declare new exceptions. Exceptions are simply given a name -- there is no further structure. Example:

zork: exception;

To find an exception handler, the runtime does a dynamic search up the calling stack -- note that this is like dynamic scoping for finding the binding of variables, and is unlike the other scoping rules in Ada.

In Ada, once an exception is raised, we can't return and resume computation -- the computation that raised the exception is terminated prematurely.

with TEXT_IO; use TEXT_IO; procedure exception_factorial is package int_io is new integer_io (integer); use int_io; function factorial(n: integer) return integer is result: integer := 1; begin for i in 1 .. n loop result := result*n; end loop; return result; exception when constraint_error => put("overflow in factorial -- n = "); put(n); new_line; return integer'last; end factorial; begin -- main program here put(factorial(5)); new_line; put(factorial(1000)); end exception_factorial; We could also propagate an exception. For example, in factorial we might replace the handler with raise FACTORIAL_ERROR; which raises a new exception (FACTORIAL_ERROR) for handling by an exception handler in some outer scope.

For a more complicated Ada example (including user-defined exceptions, propagating an exception, and recursion), click here.


Smalltalk-80 also has an exception handling mechanism, which is somewhat more flexible and powerful than Ada's. Here are some differences:

The relevant classes are in the category Kernel-Exception Handling. See Exception class>Examples for examples of use.

Exceptions are instances of class Exception. Handlers are instances of class Signal. For some reason, Smalltalk doesn't use the subclassing mechanisms here, but makes all handlers be instances of Signal. Signals have a parent field that refers to the parent signal. For example, SubscriptOutOfBoundsSignal is a child of IndexNotFoundSignal, which is in turn a child of the generic ErrorSignal. A handler for an index not found exception could also handle a subscript out of bounds exception (but not a generic error exception, or some other sort of exception such as division by zero).


When to Use Exceptions

Consider a dictionary. How should you handle missing entries? dict at: key dict at: key ifAbsent: [nil]. dict at: key ifAbsent: [^whoKnowsWhat]. Including an ifAbsent: block works well in some situations, but can become cumbersome. (What if you had to include a ifZero: block for every divide message?) The other awkwardness can be needing to pass a variety of ifAbsent blocks along through multiple calls. For both of these situations, using the exception mechanism may be more convenient.