Exception Handling Mechanisms: High-Level Error Control

Robert D. Cameron
March 1, 2002
Exceptionsare anomalous conditions that preclude the normal continuation of a computation, e.g.,

If a procedure cannot continue because of an exception, its caller might be able to handle it.

Exception handlers are particularly useful for providing software fault tolerance:

Exception Handling Constructs

Exception handling constructs were first found in PL/I and have been incorporated in a variety of more modern languages such as CLU, Ada, Eiffel, ML, Modula-3, and Java.

In general, exceptions are defined as the names of anomalous conditions:

Raising (throwing in Java) an exception signals that an anomalous condition has occurred.

An exception handler is a segment of code that is designed to be activated when the corresponding exception is raised. Typically an exception handler is associated with a segment of code and is used to handle any exceptions that arise in execution of the code.

For example in Modula-3:

EXCEPTION BadFormat;
...
TRY
  stmts
EXCEPT
  BadFormat => handler-stmts
END;
Any exception occurring within stmts immediately terminates local execution and transfers control to handler-stmts. Execution then proceeds normally following the TRY statement.

Modula-3 also provides a clean-up style of handler that catches any exception whatsoever.

TRY stmts
FINALLY cleanup-stmts
END;
Here, cleanup-stmts will always be executed even if an exception is raised in the execution of stmts. However, if such an exception is raised, then it will be re-raised after the execution of cleanup-stmts.

Modula-3 and other modern languages (e.g., CLU, Ada) statically bind handlers to particular code segments.
In PL/I, the binding of handlers is dynamic; the current handler in force for a given exception could be changed at any time under the control of the programmer.

Data Communication

When an exception is raised, how can information be passed to the handler?

  1. Using global variables: (Ada, PL/I).
    This is the simplest mechanism, but can be awkward to program and difficult to read.

  2. Using parameterized handlers: (Modula-3, CLU).
    For example in Modula-3:
    EXCEPTION BadFormat(Text);
    ...
    TRY
      stmts
    EXCEPT
      BadFormat(theString) => 
        PutText("Enter a replacement for |" 
               theString"|.")
    END;
    
    This approach is somewhat more complex and less efficient, but provides greater flexibility and readability.
  3. Using exception objects: (Java).
    public class FileNotFoundException extends IOException {
            public FileNotFoundException();
            public FileNotFoundException(String s);
    
    An elegant approach that also uses the subtype hierarchy for catching exceptions.

Exceptions and Procedure Interfaces

In general, the idea of raising an exception is to signal a condition that cannot be dealt with by the current procedure. Thus the current procedure terminates abnormally and passes the exception to its caller.

In Modula-3, CLU, and Java, the possibility that a procedure raises an exception is considered part of its input-output specification and must be explicitly declared in the procedure heading.

PROCEDURE ScanRealNumber 
             (str : Text) : REAL RAISES {BadFormat};

If a procedure terminates due to an exception, but that procedure does not specify it in the header, then

In other languages the exception may be propagated back to the caller of the procedure and the caller's caller and so on until a handler is found. This is true in Modula-3 only so long as each procedure header properly declares the exception.

Checking. Compilers can check whether clients of procedures

Exception Handling versus Error Codes

In languages without exception handling mechanisms (e.g., C, Pascal), error flags are often used to signal the occurrence of an anomaly. These error flags may be either

In either case, the programmer is explicitly responsible for checking for errors after the subprogram completes.

Exception handling mechanisms have two significant advantages over the use of error codes.

  1. Safety. What happens if an anomaly occurs in a subprogram, but the programmer has not coded any error-handling procedures to deal with it?
    1. Using the error flags approach, execution simply proceeds as if everything was OK. In this case, the program will be in a corrupted state which may eventually cause
      • a system crash (bad),
      • incorrect results to be computed (worse), or
      • corruption of data files (worst).
    2. Using the exception handling approach, the lack of a programmer-specified exception handler will cause the program to terminate gracefully and report the exception that was raised.
  2. Clarity of Algorithms. In order to systematically handle all potential anomalies in a program, the error flag approach requires that tests be included after every call that might report an anomaly. This can greatly obscure the logic of an algorithm.

    In the exception handling approach, handlers are only coded at the point where it is actually possible to handle an exception. None of the lower-level code need be obscured with the details of error handling.