next up previous
Next: A condition hierarchy Up: Stages in Common Lisp Previous: Stages in Common Lisp

function ``envelopes''

Function call/return provides an envelope for syntactically containing actions. CL also uses by default lexical scoping, but allows declarations of dynamic or ``fluid'' variables. (These could be global, but also shadowed by variable bindings of functions that have been called/still active).

In spite of its differences from C or Fortran or Java, the CL model can at least suggest how languages might treat exceptions ``conditions'' uniformly. Compiling to optimal code will not be easy in any case: let's try to express what we want, first!

(a) It provides direct production of signals (conditions), e.g.

(if (< x 0) (error "~s invalid x" x))
The function error cannot return a value.

Treatment in an interactive language, and in the absence of any other specification the user is presented with the error message, perhaps in some debugging environment.

However,

(b) errors can be trapped and ignored or values substituted for the erroneous computation.

(ignore-errors {do something})

returns either evaluation of {do something} or two values: nil and the name of a condition. Note that ignore-errors is not a primitive but can be implemented using the next facility:

(c)

  (handler-case <do something>
   (<condition-name-1>(<arg>)  <computation>)
   (<condition-name-2>(<arg>)  <computation>)
.... etc.)

(d) Other kinds of handlers are possible, including handlers that are dynamically instantiated: signaling requires that the appropriate handler be found. One can find the ``nearest'' handler which may handle or decline the signal, as well as the handler that would be next in line (can be separated from invoking them). If a handler declines, another handler is sought.

The lexical environment of the signaler might not be available, so a data structure called a "condition" is created to represent the state. This can be explicitly created via make-condition or is created by some system operation.

(e) A dynamically-bound handler for all arithmetic might be set up via

(handler-bind ((arithmetic-error xxx)) body)

Where the program xxx would be invoked if an arithmetic error occurred in executing body. The handlers (if others) that would be used by xxx are those in the dynamic context of the handler-bind.

What quality of information is provided? minimum: (error "some data string") This is fragile, hard to check, uninformative.

Better is to produce an error condition context:

   (error 'division-by-zero 
           :operator 'divide 
           :operands (list num denom))

which is given to handler. (should presumably include whatever is potentially useful. E.g. function name / location in which the error occurred.)

It is possible to instantiate a system error handler with at least some of this information (I have tried this on Sun Sparc) to produce exactly this effect for floating-point exceptions.

(Note: no standard for built-in floating-point exceptions is provided in the language spec).


next up previous
Next: A condition hierarchy Up: Stages in Common Lisp Previous: Stages in Common Lisp

Richard J. Fateman
Sat Aug 15 13:32:36 PDT 1998