let is evaluated during the expansion of the macro; it binds the symbol
bodysym. The inner let is evaluated when the resulting code is executed; it binds a symbol whose name is
Here is a simpler, mostly equivalent macro, which simply uses the symbol
(defmacro condition-case-unless-debug (var bodyform &rest handlers)
`(let ((body (lambda () ,bodyform)))
The problem with this simpler macro is that the code it expands to uses the symbol
body. This interferes with the use of
body as a variable name in the place where it is used. Instead of
body, the macro could use a symbol like
condition-case-unless-debug/body which isn't used anywhere else, but even that would fail if the macro is used multiple times, one nested in the other. Hence the macro uses
make-symbol to create a different symbol each time it is expanded. Creating fresh symbols is a common concern when writing macros that expand to code that uses temporary variables.
The difference between this macro and a plain
condition-case should be easy to see from the simplified version above: the resulting code checks the variable
debug-on-error, and if an error occurs, instead of applying the error handlers, the code lets the debugger catch the error. This can be useful while debugging error handling, but you wouldn't use it in production code.
,@ in front of a variable name is a way to expand a variable under backquotes, like
, except that it treats the value of the variable as a list and splices it. Thus in
(condition-case ,var (funcall body) ,@handlers) the variable
handlers should contain a list of handlers; this is equivalent to
(append (list 'condition-case var '(funcall body) ) handlers).