One thing that very few code samples (for any language) touch upon is error handling. There are a number of reasons for this.
- Error handling code is ugly
- It can take up a significant amount of the code
- It distracts from what the sample is trying to demonstrate
Robust code almost always needs error handling. How is it done in Emacs Lisp?
Try / Catch / Finally – The Error Handling Trinity
In Java, code that may throw an exception looks like this:
try { // Code that may throw } catch (SomeType exception) { // Handler code for SomeType } catch (Exception exception) { // Handler code for Exception } finally { // Code to execute after // Code + the handler if any }
The finally clause handles the clean-up and is always executed whether or not an exception is thrown.
How Emacs Lisp Does It
Emacs Lisp has an equivalent for each part – from throwing the exception, to catching it and handling clean-up. (error ...) throws the most basic exception (in emacs lisp, they are called signals). If you execute an error call without protecting it, emacs will enter the debugger.
unwind-protect
unwind-protect is the emacs way of implementing a finally clause. In the following code, when you exit from the debugger, hi will be inserted in the buffer.
(unwind-protect (error "hello") (insert "hi"))
condition-case
Try/Catch is spelled condition-case. There is one handler per signal we want to handle. All signals are derived from ‘error so catching error catches any remaining signals.
(condition-case var bodyform &rest handlers)
(unwind-protect (let (retval) (condition-case ex (setq retval (error "Hello")) ('error (message (format "Caught exception: [%s]" ex)))) retval) (message "Cleaning up..."))
We can wrap this all in a macro. Adapt the following for your own use.
(defmacro safe-wrap (fn &rest clean-up) `(unwind-protect (let (retval) (condition-case ex (setq retval (progn ,fn)) ('error (message (format "Caught exception: [%s]" ex)) (setq retval (cons 'exception (list ex))))) retval) ,@clean-up))
Some Examples
(safe-wrap (error "Hello") (message "Unwinding...")) Caught exception: [(error Hello)] Unwinding... (exception (error "Hello")) ;; return value ;; (safe-wrap (message "Hello") (message "Unwinding...")) Hello Unwinding... "Hello" ;; return value (safe-wrap (/ 1 0)) Caught exception: [(arith-error)] (exception (arith-error)) ;; return value
If you liked this post, why not subscribe to my RSS feed.
Very cool. Subscribed
Hey df, thanks very much. But you were a subscriber already right?
Yeah, I was trying to drum up grassroots support
I didn’t get any new subscribers for this one, but I did for the waffley “A Modern Style of Programming”. I’m not sure why :-/ Anyway, thanks for trying df
Hi,
I have subscribed. This was the first post that I came across when I searched in Google blog search and then I went through the other entries. Your blog is impressive !!! keep up the good work !!!
I subscribed as well. Great post!
Your article is nice as an introductory article to Emacs Lisp handling of errors. However, you have left out how do you learn what signals a function could raise.
Thanks.
I think the line
((quote error) (message (format “Caught exception: [%s]” ex))))
can be simplified to
(error (message “Caught exception: [%s]” ex)))
i know this post is old, but it still was the first one, which popped up for the search terms “emacs error handling finally”. this article kind of misses the point of unwind-protect: when you catch every error, there is no real point of wrapping it with unwind-protect. using progn instead of unwind-protect achieves the same output of course.
unwind-protect is useful if you don’t want to catch the error at this level in the code but only later and still clean up in the mean time:
(condition-case ex
(unwind-protect
(error “Hello”)
(message “Cleaning up…”))
(‘error (message (format “Caught exception: [%s]” ex))))
will run cleaning up. and catch the exception afterwards.
cheers,
jonas