Common Lisp the Language, 2nd Edition


next up previous contents index
Next: Trapping Errors Up: Survey of Concepts Previous: Survey of Concepts

29.3.1. Signaling Errors

change_begin
Conceptually, signaling an error in a program is an admission by that program that it does not know how to continue and requires external intervention. Once an error is signaled, any decision about how to continue must come from the ``outside.''

The simplest way to signal an error is to use the error function with format-style arguments describing the error for the sake of the user interface. If error is called and there are no active handlers (described in sections 29.3.2 and 29.3.3), the debugger will be entered and the error message will be typed out. For example:

Lisp> (defun factorial (x) 
        (cond ((or (not (typep x 'integer)) (minusp x)) 
               (error "~S is not a valid argument to FACTORIAL." 
                      x)) 
              ((zerop x) 1) 
              (t (* x (factorial (- x 1)))))) 
 => FACTORIAL 
Lisp> (factorial 20) 
 => 2432902008176640000 
Lisp> (factorial -1) 
Error: -1 is not a valid argument to FACTORIAL. 
To continue, type :CONTINUE followed by an option number: 
 1: Return to Lisp Toplevel. 
Debug>

In general, a call to error cannot directly return. Unless special work has been done to override this behavior, the debugger will be entered and there will be no option to simply continue.

The only exception may be that some implementations may provide debugger commands for interactively returning from individual stack frames; even then, however, such commands should never be used except by someone who has read the erring code and understands the consequences of continuing from that point. In particular, the programmer should feel confident about writing code like this:

(defun wargames:no-win-scenario () 
  (when (true) (error "Pushing the button would be stupid.")) 
  (push-the-button))

In this scenario, there should be no chance that the function error will return and the button will be pushed.


Remark: It should be noted that the notion of ``no chance'' that the button will be pushed is relative only to the language model; it assumes that the language is accurately implemented. In practice, compilers have bugs, computers have glitches, and users have been known to interrupt at inopportune moments and use the debugger to return from arbitrary stack frames. Such violations of the language model are beyond the scope of the condition system but not necessarily beyond the scope of potential failures that the programmer should consider and defend against. The possibility of such unusual failures may of course also influence the design of code meant to handle less drastic situations, such as maintaining a database uncorrupted.-KMP and GLS

In some cases, the programmer may have a single, well-defined idea of a reasonable recovery strategy for this particular error. In that case, he can use the function cerror, which specifies information about what would happen if the user did simply continue from the call to cerror. For example:

Lisp> (defun factorial (x) 
        (cond ((not (typep x 'integer)) 
               (error "~S is not a valid argument to FACTORIAL." 
                      x)) 
              ((minusp x) 
               (let ((x-magnitude (- x))) 
                 (cerror "Compute -(~D!) instead." 
                         "(-~D)! is not defined." x-magnitude) 
                 (- (factorial x-magnitude)))) 
              ((zerop x) 1) 
              (t (* x (factorial (- x 1)))))) 
 => FACTORIAL 
Lisp> (factorial -3) 
Error: (-3)! is not defined. 
To continue, type :CONTINUE followed by an option number: 
 1: Compute -(3!) instead. 
 2: Return to Lisp Toplevel. 
Debug> :continue 1 
 => -6


change_end



next up previous contents index
Next: Trapping Errors Up: Survey of Concepts Previous: Survey of Concepts


AI.Repository@cs.cmu.edu