2

I have a question about macros. When I call a macro with an argument, I call a function with it. It works. But if I add another instruction below, the backquoted instruction is not executed.

Here is the dummy example:

(setq words '())

(defun func-test (name)
  "Function test."
  (message "Function called with %s" name)
  (add-to-list 'words name))

(defmacro macro-test (name)
  "Macro test."
  (message "Before ...")
  (unless (member name words)
    `(func-test ,name))
  ;;;; /!\ Bug: if I uncomment this next line, it does not work anymore
  ;;(message "... After")
  )

(macro-test 'hello)
(message "%S" words)
;; Should be (hello)

(macro-test 'thanks)
(message "%S" words)
;; Should be (thanks hello)

(macro-test 'bye)
(message "%S" words)
;; Should be (bye thanks hello)

Do you have any idea or tip to deal with it?

Bonus question: can I use several backquoted instructions in this macro or is there a specific form to use it? E.g. if I want to call several functions from my macro.

3

You are probably aware that macros get evaluated at macro-expansion-time which isn't the same as run-time (that's why you are not just using a function in the first place). When a macro is "first evaluated" at macro-expansion-time it returns a form which later gets evaluated at runtime.

In your macro-test macro the last form is (message "... After"). At macro-expansion-time it is evaluated which results in "... After" being shown in the echo area (which you shouldn't do except for debugging purposes) and the same string being returned - first by the message form, and then because that is the last form in the macro body, also by the macro being expanded. That string then becomes the macro expansion. Evaluating a string has no side-effect, so nothing happens.

The form which is supposed to be evaluated at run-time has to be the last form in the macros body. Think of the macro as a function which just happens to be evaluated at some other time. If you want a function to return a value then you have to make sure that the last form in its body actually returns that value - it's exactly the same with macros.


To make a macro which expands to calls to several functions just return a form which does that, e.g.

(defmacro foo (arg)
  `(progn (bar ,arg)
          (baz)))
  • Thank you very much for this clear and instructive (as in "well explained") answer. it totally makes sense ... now that you told it this way :) – DCLaoij Mar 17 '15 at 13:13

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.