screwlisp proposes kittens

Handling errors in ANSI Common Lisp: An example

One piece of secret alien technology that is still in the future of non-lisp languages is Kent Pitman’s condition system. Particularly, lisp can be called with outside handlers that handle the condition or error from inside the stackframe where it was signalled/happened.

Trying to add non-numbers

(defun two-arg-plus (no1 no2)
  (check-type no1 number)
  (check-type no2 number)
  (+ no1 no2))
(two-arg-plus 1 "2!")

in lisp this gets me somewhere like:

The value of NO2 is "2!", which is not of type NUMBER.
   [Condition of type SIMPLE-TYPE-ERROR]

Restarts:
 0: [STORE-VALUE] Supply a new value of NO2
 1: [RETRY] Retry SLIME REPL evaluation request.
 2: [*ABORT] Return to SLIME's top level.
 3: [RESTART-TOPLEVEL] Go back to Top-Level REPL.

Backtrace:
  0: LAMBDA1155
  1: #<bytecompiled-function TWO-ARG-PLUS 0x7f4f4169f0a0>
      Locals:
        NO1 = 1
        NO2 = "2!"
        #:G3816 = "2!" etc etc

Note that I opened frame 2 there in my debugger software (emacs slime) to see the locals. (ANSI CL defines a debugging protocol, so software that uses that protocol is implied by the standard).

Common lisp hyperspec example for here

The hyperspec is beyond comparison the best example, explanation and demonstration of ansi common lisp’s condition handling / error handling facilities. It is somewhat interesting to read the 18th revision of Kent’s antecedent work to ANSI CL and the hyperspec: https://www.nhplace.com/kent/CL/Revision-18.txt .

From https://www.lispworks.com/documentation/HyperSpec/Body/f_tp_err.htm#type-error-datum :

Note that in emacs slime you can get to this page by typing M-x c-l-hy with the cursor near the thing you want to learn about.

 (defun fix-digits (condition)
   (check-type condition type-error)
   (let* ((digits '(zero one two three four
                   five six seven eight nine))
         (val (position (type-error-datum condition) digits)))
     (if (and val (subtypep 'fixnum (type-error-expected-type condition)))
         (store-value val))))
 
(defun foo (x)
   (handler-bind ((type-error #'fix-digits))
     (check-type x number)
     (+ x 3)))

though in my case I was trying to deal with a string number.

If I get a string, just call parse-integer allowing junk on it

(defun parse-string-numbers (condition)
  (check-type condition type-error)
  (check-type (type-error-datum condition) string)
  (let ((no (parse-integer
	     (type-error-datum condition)
	     :junk-allowed t)))
    (if (numberp no) (store-value no))))

Using our parse-string-numbers to deal with simple-type-error in our two-arg-plus (or anywhere)

(handler-bind
    ((type-error #'parse-string-numbers))
  (two-arg-plus 1 "2!"))

Completely separating explicitly handling runtime errors from rewriting the erroring program is fundamentally important

If we contrast the wildly popular agile management strategy:

  1. Write a program
  2. The program has an error
  3. goto 1

with

  1. Write a program
  2. Program has an error
  3. Write a handler for the error
  4. Run the program with the handler(s) for the error(s)
  5. Everything is great.

The latter is categorically superior and it is not close.

Fin.

This article was obviously apropos Kent Pitman demoing his implementation of his error handling for common lisp ported to python, though the separating error-handling half-programs is a clear and unequivocal categorical improvement over the agile management just-rewrite-the-underlying-code error handling theory.

The stream is at 8am Zulu time (800UTC,9am CET) Sunday (December, 14th, 2025).

The video live stream of Kent Pitman’s his lisp style error handling in python will be at: https://toobnix.org/w/gXLXQqxf5MYg1NDF2Ua6oA (as it is every week around this time), with the video on demand afterwards.

You could watch the show mastodon for the announcement.

Mastodon toot thread for this article. Do you do the sophisticated error handling?

screwlisp proposes kittens