1
(defmacro condition-case-unless-debug (var bodyform &rest handlers)
  (let ((bodysym (make-symbol "body")))
    `(let ((,bodysym (lambda () ,bodyform)))
       (if debug-on-error
           (funcall ,bodysym)
         (condition-case ,var
             (funcall ,bodysym)
           ,@handlers)))))

I am trying to deep-dive into this macro definition and I have many questions:

  1. This macro uses nested let blocks instead of a single let block? And doesnt the inner let block's bodysym variable always override the outer bodysym variable?

  2. How is condition-case-unless-debug different from condition-case? Sorry folks, the elisp doc is not clear enough.

  3. @handlers ---> what does @ symbol before a variable name stand for?

2
  • See Paul Graham's book (free) On Lisp, chapters 7-16. You need not read all of that, however, to get the point about the question you ask.
    – Drew
    Feb 23, 2015 at 0:38
  • This question would have been better broken up into multiple questions to allow for clear answers: The first and third questions are regarding backquote expansion (and unique symbols). The 2nd question is regarding the differences between two functions. Leaving open since Gilles did address all the points one by one. Feb 23, 2015 at 15:37

1 Answer 1

2

The outer 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 body.

Here is a simpler, mostly equivalent macro, which simply uses the symbol body:

(defmacro condition-case-unless-debug (var bodyform &rest handlers)
  `(let ((body (lambda () ,bodyform)))
     (if debug-on-error
         (funcall body)
       (condition-case ,var
           (funcall body)
         ,@handlers))))

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).

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.