2

In Section 13.5.4 of the Elisp reference, we are shown a problem whereby a macro definition evaluates one of its argument expressions.

(defmacro foo (a)
  (list 'setq (eval a) t))
(setq x 'b)
(foo x) → (setq b t)
     ⇒ t                  ; and b has been set.
;; but
(setq a 'c)
(foo a) → (setq a t)
     ⇒ t                  ; but this set a, not c.

We are then advised to

substitute the expression into the macro expansion, so that its value will be computed as part of executing the expansion.

I'm not sure what this means, but I interpret it as meaning that we should try to rewrite the macro as follows:

(defmacro foo (a)
  `(setq (eval ',a) t))

Which, when expanded, gives:

(macroexpand '(foo x)) → (setq (eval (quote x)) t)

But I'm getting the following error when I call (foo x):

(wrong-type-argument symbolp (eval (quote x)))

Even though when I evaluate (symbolp (eval (quote x))), the result is t.

It seems that there's something fundamental that I'm not understanding here. What's the issue?

  • It's a typo in the manual, it should read: "but this set c, not a." You might want to write about it to Emacs ailing list. – wvxvw Dec 15 '15 at 6:12
  • @wvxvw: No, I don't think so. It sets a, not c. (But there is a typo: "set" should be "sets".) – Drew Dec 15 '15 at 6:23
  • @Drew Oh, I see now, I've missed the whole point of this article :) Yeah, it's not a typo. I just wasn't careful to read it through. – wvxvw Dec 15 '15 at 8:21
0
  1. setq does not evaluate its first argument, so your second defmacro definition cannot work. The error message tells you that setq expects a symbol as its first argument, but you passed it the list (eval (quote x)) instead.

  2. The problem with the original code is that there is variable capture: the parameter of the defmacro is a, as is the variable passed to foo.

  • Ah, of course, this looks like a job for set instead! And the modified macro with set does seem to work properly, including for "a" where (setq a 'c). Two questions: how are we avoiding variable capture, and don't we still have the issue of expansion during byte-compilation? How should a macro that does what we want be written? – Tianxiang Xiong Dec 15 '15 at 14:28
  • To avoid variable capture, the code produced by macroexpansion (and then evaluated) needs to bind new variables. See the Elisp manual, node Surprising Local Variables. (See also the other nodes about defining Lisp macros.) – Drew Dec 15 '15 at 15:13
  • What "issue of expansion during byte-compilation"? – Drew Dec 15 '15 at 15:13
  • From the same node: Another problem with calling ‘eval’ in a macro definition is that it probably won’t do what you intend in a compiled program. The byte compiler runs macro definitions while compiling the program, when the program’s own computations (which you might have wished to access with ‘eval’) don’t occur and its local variable bindings don’t exist. – Tianxiang Xiong Dec 15 '15 at 17:01
  • The way I understand it, if we have (eval a) in the macro as in the original example, the byte-compiler tries to expand the macro when the file is compiled, but a is not yet defined. I'm assuming the backquote-comma construct has the same problem, since "comma" is basically a marker shorthand for eval? – Tianxiang Xiong Dec 15 '15 at 17:08

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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