The Revised Maclisp ManualThe PitmanualPage A-21
Published by HyperMeta Inc.
 
Prev | Index | Next
[Blue Marble]
Climate Change
How can we measure whether
the solutions we attempt are working?


Error Handlers

Signalling Errors


ERRORFunction(ERROR [msg [datum [kwd]]])

This is a function which allows user functions to signal their own errors using the LISP error system.

The simplest useful way to signal an error is by just specifying an error message. The message, msg, is typed out using PRINC.

(defun loser () (error "You lost in function LOSER"))
=> LOSER

(loser)
;You lost in function LOSER

;; Here's another example...
(defvar *the-stack* '() "A stack")
=> *THE-STACK* 

(defun push-stack (x) (push x *the-stack*) x)
=> PUSH-STACK

(defun pop-stack ()
  (cond (*the-stack* (pop *the-stack*))
        (t (error "The stack was empty!"))))

=> POP-STACK

(push-stack 4)
=> 4

(pop-stack)
=> 4

(pop-stack)
;The stack was empty!

It is also possible to supply a datum which will be typed out ahead of the message using PRIN1.

;; Type checking an argument
(defun foo (x)
  (if (or (not (numberp x)) (oddp x))
      (error "Odd argument to FOO" x))
  (times x x))
=> FOO

(foo 4)
=> 16

(foo 3)
;3 Odd argument to FOO

It is possible also to signal a “correctable” error by specifying a keyword, kwd, which identifies the class of error. The keyword may be one of the symbols UNDF-FNCTN, UNBND-VRBL, WRNG-TYPE-ARG, UNSEEN-GO-TAG, WRNG-NO-ARGS, GC-LOSSAGE, IO-LOSSAGE, or FAIL-ACT. If there is a handler for that class of error, it is called with one argument: a list whose first element is datum. If it returns NIL, it could not correct the error and ERROR does not return; instead, the stack is unwound to the point of the last ERRSET or to Lisp toplevel. However, if the handler returns something other than NIL, it should be a list whose car is the value to be returned by ERROR. It is wise to double-check the result which is returned in case it still isn't correct.

(defun factorial (x)
  (do () ((and (fixp x) (not (minusp x))))
    (setq x (error "Bad arg to FACTORIAL" x 'wrng-type-arg)))
  (do ((r 1 (times r i))
       (i x (sub1 i)))
      ((zerop i) r)))
=> FACTORIAL

(factorial 4)
=> 24.

(factorial -3)
;-3 Bad arg to FACTORIAL
;BKPT WRNG-TYPE-ARG
(return '(-4))
;-4 Bad arg to FACTORIAL
;BKPT WRNG-TYPE-ARG
(return '(7))
=> 5040.	

If the error handler can successfully recover from the error, no typeout is done by ERROR; it is as if the error never occurred. The entry to the breakpoints in the above examples are brought on by the system default handlers, not by error itself. It is possible to write error handlers which do not require user intervention.

If the handler was null, or if the handler returns an atom, error goes ahead and signals a regular error, returning to the innermost ERRSET (if one exists) or typing out an error message and unwinding the stack if no ERRSET surrounds the call to ERROR.

Errors of a special purpose kind might in some cases be better handled using *CATCH and *THROW.

Note: For historic reasons, the third (keyword) argument to ERROR is sometimes referred to as an “error channel.”


ERRORStyle NoteProviding error info

The form (ERROR) is essentially the same as the obsolete (ERR). It provides no useful debugging info and should be avoided.

Code intended for release, exportation, etc., should call ERROR with three arguments, specifying an error channel and accepting correction information from the user-interrupt handler. Many Maclisp users consider it `rude' to use fewer than three arguments to ERROR. Sadly, the Maclisp system itself, particularly in the reader, often calls ERROR without specifying a user interrupt channel; this means that ERRSET is about the only way to trap READ errors; there is no graceful way to recover from a READ error.


ERRSpecial Form(ERR [form [flag]])

Archaic. Use ERROR instead.

If form is not supplied, causes an error which is handled the same as a LISP error except that there is no handler function invoked which might potentially correct the error.

If form is supplied, then if control is returned to an ERRSET, then the value of the ERRSET will be the result of evaluating form rather than the NIL which would otherwise be returned by the ERRSET.

The flag is not evaluated. If supplied and not NIL (a flag of NIL is the same as omitting flag), then the form to be returned from an ERRSET will not be evaluated until just before the ERRSET returns it. That is, form is evaluated after unwinding the pdl and restoring the bindings.

Note: It doesn't look like (ERR form NIL) really is the same as (ERR form), empirically. Good luck with it.

Note: Some very old code uses ERR and ERRSET where *CATCH and *THROW are indicated. This is a very poor programming practice and code like this should be brought up to date.


CERRORFunction(CERROR proceedp restartp cond msg . args)

[PDP-10 Only] Signals a continuable error.

This was introduced primarily for NIL and Lisp Machine Lisp compatibility. However, since those languages continue to evolve and Maclisp tends to remain more stable these days, ERROR should probably be preferred. It is probably the case that NIL and Lisp Machine have much better compatibility support for ERROR than vice versa anyway.


FERRORFunction(FERROR cond msg [data1 [data2 ...]])

Signals a fatal error.

This was introduced primarily for NIL and Lisp Machine Lisp compatibility. However, since those languages continue to evolve and Maclisp tends to remain more stable these days, ERROR should probably be preferred. It is probably the case that NIL and Lisp Machine have much better compatibility support for ERROR than vice versa anyway.

Synonym:

(CERROR NIL NIL cond msg [data1 [data2 ...]])

Trapping Errors


ERRSETSpecial Form(ERRSET form [flag]).

ERRSET evaluates its first argument. If no errors occur, a list whose first element is the result is returned. If an error occurs during the evaluation of the first argument, the error is prevented from escaping from inside the ERRSET and ERRSET returns NIL. If a second argument is given to ERRSET, that argument is not evaluated. If it is NIL, no error message will be printed if an error occurs during the evaluation of errset's first argument. If the second argument is not NIL, or if ERRSET is used with only one argument, any error messages generated will be printed.

ERRSET may be made to return any arbitrary value by use of the err function. This is a compatibility hack to support very old code (from before catch/throw existed) and is strongly discouraged.

See also: ERROR, *CATCH, *THROW

(errset (+ 'a 3) nil)
=> NIL

(errset (+ 'a 3) t)
;A NON-NUMERIC VALUE
=> NIL

(errset (+ 'a 3))
;A NON-NUMERIC VALUE
=> NIL

(errset (+ 4 3))
=> (7)

Examples:

(setq x 3.0)			=> 3.0
(defun f (y) (+ y y))		=> F
(errset (add1 x) NIL)		=> (4.0) ; add1 succeeded
(errset (f x) NIL)		=> NIL   ; f err'd: 3.0 not fixnum
(errset (f (fix x)) NIL)	=> (6)	 ; f succeeded
(defun kar (x)
       (car
        (errset (car x) NIL)))	=> KAR
(kar '(a b))			=> A
(kar 'a)			=> NIL
(kar 3)				=> NIL

ERRSETValueNIL

The value of the symbol ERRSET, if not NIL, is a handler for the condition which is signalled when an error is caught by an ERRSET.

Error Channels


UNDF-FNCTNValue+INTERNAL-UDF-BREAK

The value of this symbol, if not NIL, is the handler function for the condition which is signalled when an attempt is made to call an undefined function.

The function should take one argument. The argument it receives will be a cons, the car of which is the offending function and the cdr of which is NIL. If it successfully corrects the error, it should return a cons which contains in its car the function (a symbol or lambda expression) to be used instead. If it could not correct the error, it should return NIL.

The handler may return its argument if the offending function has become defined during the run of the handler.

To save consing, it is also permissible to RPLACA a new function name into the cons which was received as an argument and return that form.


UNBND-VRBLValue+INTERNAL-UBV-BREAK

The value of this symbol, if not NIL, is the handler function for the condition which is signalled when an attempt is made to evaluate a symbol which is not bound.

The function should take one argument. The argument it receives will be a cons, the car of which is the offending variable name and the cdr of which is NIL. If it successfully corrects the error, it should return a cons which contains in its car the symbol to be re-tried. If it could not correct the error, it should return NIL.

The handler may return its argument if the offending symbol has been given a value during the run of the handler.

To save consing, it is also permissible to RPLACA the new symbol into the cons which was received as an argument and return that form.


WRNG-TYPE-ARGValue+INTERNAL-WTA-BREAK

The value of this symbol, if not NIL, is the handler for the condition which is signalled when an argument is passed to a function which is not acceptable to that function.

The argument is a cons whose car is the erring datum. Any other debugging information (such as the kind of error) should be picked up from a call to ERRFRAME.

The handler should return a cons whose car is the corrected datum to be retried or NIL if it could not correct the error.

To save consing, it is also permissible to RPLACA the result into the cons which was received as an argument and return that form.


UNSEEN-GO-TAGValue+INTERNAL-UGT-BREAK

The value of this symbol, if not NIL, is the handler for the condition which is signalled when a GO is done to a tag which is not seen in the currently accessible PROG frame, or when a THROW or *THROW is done to a tag for which there is no catch frame.

The function should take one argument. The argument it receives will be a cons, the car of which is the offending tag and the cdr of which is NIL. If it successfully corrects the error, it should return a cons which contains in its car the tag to be re-tried. If it cannot successfully correct the error, it should return NIL.

To save consing, it is permissible to RPLACA the new tag into the cons which was received as an argument and return that form.


WRNG-NO-ARGSValue+INTERNAL-WNA-BREAK

The value of this symbol, if not NIL, is the handler function for the condition which is signalled when a function is called with the wrong number of arguments.

The function should take one argument. The argument it receives will be a list, the car of which will be the offending form and the cadr of which is the args information (for compiled functions) or the bound variable list (for interpreted functions). If it successfully corrects the error, it should return a cons which contains in its car the value to be used in place of evaluating the erring form. If it cannot successfully correct the error, it should return NIL.

To save consing, it is permissible to RPLACA the value into the cons which was received as an argument and return that form.


GC-LOSSAGEValue+INTERNAL-GCL-BREAK

The value of this variable, if not NIL, should be a handler function for the condition which is signalled when there is no more memory.

In the Multics implementation, there is always enough memory, so this condition never occurs. (Actually, if you do run out of memory, the effects are devastating and Lisp never bothers to call this interrupt handler.)

*** What is the argument-convention for this handler? ***


FAIL-ACTValue+INTERNAL-FAC-BREAK

The value of this variable, if not NIL, should be a handler function for the condition which is signalled when any of a wide variety of miscellaneous error conditions occurs.

Author's note: It has been claimed that the function and return value conventions for this are far too confused to really work. Innovative solutions to recovery such as just throwing to known-to-be-available catch tags may be the only way to gracefully recover from such errors. When bad values are seen for things like IBASE, BASE, etc., this handler may take control. It may be worthwhile checking important system variables in this handler to make sure they have valid values.


IO-LOSSAGEValue+INTERNAL-IOL-BREAK

[PDP-10 Only] The value of this variable, if not NIL, should be a handler function for the condition which is signalled when there is some sort of operating-system signalled error during I/O.

*** What is the argument-convention for this handler? ***

Other Condition Handlers


MACHINE-ERRORValueNIL

[PDP-10 Only] The value of this variable is a handler to be run if Lisp signals some form of machine error.

*** What is the argument-convention for this handler? ***


PDL-OVERFLOWValue+INTERNAL-PDL-BREAK

The value of this variable is a function of 1 argument to be run when a PDL-OVERFLOW condition is signalled.

*** What is the argument-convention for this handler? ***

Error Recovery


ERRLISTValueNIL

The value of ERRLIST is a list of forms which are evaluated when control returns to top level either because of an error or when an environment is initially started. For restarting after an error, the value of ERRLIST prior to the unwinding of the stack is used, but the forms are not evaluated until after the stack is unwound. (See also the variable //).

This feature was intended to provide self-starting LISP environments and to provide special error handling for subsystems written in Maclisp. (See also (SSTATUS TOPLEVEL ...).)


//ValueNIL

The value of the symbol // is used as a temporary by the Maclisp error mechanism to buffer the value of ERRLIST between the time an error is signalled and the value of ERRLIST is used. Just prior to unwinding the stack, (SETQ // ERRLIST) is done, and after unwinding, a (MAPC #'EVAL //) is performed. Binding // is liable to totally baffle poor Maclisp.

Diagnosing Errors


ERRFRAMEFunction(ERRFRAME pdlptr)

Returns a list describing an error which has been stacked up because of an error condition, or NIL if no error is found. (See also EVALFRAME.)

If pdlptr is NIL, ERRFRAME returns the most recent error on the stack.

If pdlptr is a negative fixnum, it should be a pdl pointer, in which case the stack is searched backward from the indicated position. Thus the second most recent error may be found by

(ERRFRAME (CADR (ERRFRAME NIL))).

If pdlptr is a positive fixnum, it should be the arithmetic negation of a pdl pointer. In that case, the stack is searched forward from the indicated position.

If a list is returned, it will have the form: (ERR pdlptr errordata alist) The token ERR at the head of the form is for compatibility with the format of the object returned by EVALFRAME.

pdlptr is a pdl pointer (negative fixnum) which describes the location in the control pdl of the error. This argument may be useful as an argument to EVALFRAME and ERRFRAME.

errordata is a list of from one to three things which could be used in conjunction with APPLY to regenerate the error, as in (APPLY #'ERROR (CADDR (ERRFRAME ...))).

alist is an alist pointer (fixnum pointer into the spec pdl). This may be useful, for example, as a second argument to EVAL or a third argument to APPLY to cause evaluation using the bindings in effect just before the error occurred.


ERROR-BREAK-ENVIRONMENTValue(#.(GET 'OBARRAY 'ARRAY) . #.(GET 'READTABLE 'ARRAY))

[PDP-10 Only] A special variable which holds a CONS of an obarray and readtable to use during the system-supplied ^B Break and error handlers. This may be especially useful to the person who is debugging his macros during the compilation of some file, and wants a different debugging environment than the compiler's OBARRAY/READTABLE.


ERRPRINTFunction(ERRPRINT pdlptr [fileobj])

Errprint treats its argument the same as ERRFRAME. The message portion of the error frame is displayed (with the datum portion if there was one). Returns T if a message was typed out and NIL if no error frame was found. The second argument, fileobj, designates where to print the message. It defaults to T, the terminal.


AutoloadConceptLoading “By Need”

The “autoload” feature provides the ability for a function not present in the environment to be automatically loaded in from a file the first time it is called. EVAL, APPLY, FUNCALL, and the version of APPLY used by compiled LISP find the function definition for a symbol on its property list by looking for a SUBR, LSUBR, FSUBR, EXPR, FEXPR, ARRAY or AUTOLOAD property. If the property found is AUTOLOAD, automatic loading of the file which is the value of that property will occur. The autoload handler, which accomplishes this loading, is found in the value cell of the symbol AUTOLOAD. When the handler returns, it is expected to have put a functional property on the property list of the function being autoloaded. If no such property is found, an UNDF-FNCTN error will occur with a message such as “FUNCTION UNDEFINED AFTER AUTOLOAD.”

;; Sample setup to make FOO autoload 
;; from PS:<MYDIR>FOO.FASL (Tops-20) or MYDIR;FOO FASL (ITS)
(DEFPROP FOO ((PS MYDIR) FOO FASL) AUTOLOAD)

AUTOLOADValue+INTERNAL-AUTOLOAD

[PDP-10 Only] This variable holds the handler for the Autoload mechanism. Many programs make assumptions about how autoloading will work, so any customizations made by the user should be made in an upward-compatible way (i.e., with the intent of extending, not changing, existing functionality).


[Blue Marble]
Climate Change
Why not a carbon tax?

The Revised Maclisp Manual (Sunday Morning Edition)
Published Sunday, December 16, 2007 06:17am EST, and updated Sunday, July 6, 2008.
Prev | Index | Next