2008年1月10日 星期四

例外處理 (3):Exceptions and exception handling mechanisms

Exception is an abstraction of errors and failures. As such, an exception carries information about the errors or failures it represents. Exception handling is the programmed activities conducted among multiple collaborating components in a program in response to an exception. These activities are conducted by code units called exception handlers or handlers. A handler can be attached to a statement, a block, a method, an object, a class, a module, or an exception. The plan about how to choose or devise an exception to represent errors and failures and how to respond to an exception is called exception handling design. An exception handling mechanism (EHM) is a programming language’s fundamental supports for dealing with exceptions, including representation, definition, signaling, propagation, resolution, and continuation of exceptions.

An important objective in the design of EHM is to keep separated the code for delivering normal functionalities and the code for dealing with exceptional conditions. In a language that lacks adequate EHM support, programs explicitly check each function call on the return code, data fields, flags, or global variables for finding out about the execution status. Since the checks and handling of anomalies are mixed with the logic for normal functionalities, code becomes cluttered and the program becomes incomprehensible. EHMs in modern programming languages provide better supports for separation of concerns in this regard. With exceptions, it is no longer needed to check every statement for error state. Once the execution of a statement gives rise to an exception, the runtime environment automatically alters the program execution from a normal path to an exceptional path. This allows the programmer to structure the logic for exception handling in appropriate exception handling constructs without cluttering the program.
Exception representation is the way that a programming language expresses an exception internally. It defines an exception context which contains information explicitly passed by the exception creator or implicitly passed by the language runtime. An exception can be represented as a symbol, a data object, or a full object [1]. Exceptions defined as symbols are strings or numbers. Data-object exceptions are primarily used to hold error and failure information only. Full-object exceptions directly encapsulate signaling, propagation, and continuation behaviors of exceptions in the class definition.

Programmers use exception definition to define exceptions in a program. If exceptions are represented as symbols, new exceptions are defined as strings or numbers. If exceptions are data objects and full objects, a class is used to define an exception. Some languages allow any class to be exceptions while others require that only particular types of classes can be exceptions. For example, in C++ any class can be exceptions but in Java only classes which directly or indirectly inherit from Throwable class can be exceptions.
An exception occurrence is an instance of an exception. The instruction to explicitly transmit an exception occurrence to the exception receiver is called throwing, signaling, raising, or triggering an exception. The sender of the exception is called signaler; the receiver of an exception is called the exception target, or target. An explicit throw instruction creates a synchronous exception, which is a direct result of performing the instruction. Conversely, an asynchronous exception can occur at any time in spite of the program statements under execution. Asynchronous exceptions can be produced by the runtime environment upon encountering an internal error or by stopping or suspending a thread.

If an exception is signaled and not coped with locally, the exception can be propagated to the caller of the signaling method. Exception propagation can be explicit or implicit (or automatic). In the former, a receiver must explicitly re-throw an unhandled received exception for further propagation; in the latter, an unhandled exception is automatically propagated. An exception is internal if it is not propagated; otherwise it is external. Some languages require propagated exceptions to be declared in signatures while others allow exceptions to be propagated without declaration.

Exception resolution or handler binding is a process of finding a suitable handler in the target, which is resolved by static scoping at compiler-time, dynamic invocation chain at runtime, or both. There are two methods to dynamically find a handler: stack unwinding and stack cutting. Stack unwinding pops the stack frames to search for the matching exception handler while stack cutting maintains a list of registered exception handlers and looks up the list for a suitable exception handler. While stack unwinding incurs no overhead in the normal execution, a significant overhead is involved in the exceptional execution. In contrast, stack cutting requires some housekeeping overhead to register and deregister exception handlers in the normal execution but incurs only a relatively minor overhead in the exceptional execution.
An exception continuation or exception model specifies the execution flow after an exception handler returns its control. In the termination model or the nonresumptive model, the execution of the component is terminated. A variation of the termination model is the retry model where the original execution is terminated and then the component is engaged for execution again. In the resumption model, the execution continues from the location or the next location where the exception was raised. Although program languages can support more than one model, mainstream programming languages such as C++, Java, and C# favor the termination model for its simplicity.

  1. A. F. Garcia, C. M. F. Rubira, A. Romanovsky, and J. Xu, A comparative study of exception handling mechanisms for building dependable object-oriented software, Journal of Systems and Software, vol. 59, no. 2: 197-222, 2001.