Errors generated by the Lisp system, rather than the application domain, are a little harder to deal with.
Suppose your application performs an operation upon a file. The application calls a system function to complete this operation, so when there is no error system, any errors it generates must be caught by the application itself.
The best solution to this problem is to wrap an
abort
restart around the operation. For example:
(defun load-knowledge-base (name pathname)
(restart-case
(internal-load-knowledge-base name pathname)
(abort ()
(capi:display-message
"Failed to load knowledge base ~a from file ~a"
name (namestring pathname))
nil)))
Another solution would be to use a handler, as in the example below:
(defun my-handler (type &rest args)
(if (symbolp type)
(apply 'capi:display-message
"An error of type ~A occured, args ~A"
type args)
(apply 'capi:display-message args)))
The disadvantage of this approach is that the message is unclear.
In general, the application should not cause Lisp errors. Because it is difficult to ensure that these never happen, it is a good idea for the application to wrap an error handler around all its code. For example:
(handler-bind ((error 'application-handler-error))
(loop
(catch 'application-error
(setup-various-things)
(do-various-things))))
(defun application-handler-error (condition)
(when *application-catch-errors*
(progn (give-some-indication-of-error)
(do-some-cleanup)
(throw 'application-error nil))))
(when
*application-catch-errors*
is
nil
, this just returns and then the debugger is invoked).
In addition, the areas that are more prone to errors should be dealt with specifically. For example, file access is prone to error, so it should wrapped with error handling.