Difference between calling function and macro inside macro?

clojure, macros

Solution

`macro2` doesn't call `macro1`. Look at its body:

`(macro1 ~x)
(func1 x)

The first line is syntax-quoted; its value is list structure of the form `(user/macro1 x-value)` (assuming `macro1` is defined in the `user` namespace; `x-value` here is the literal argument provided to `macro2`) and it has no side effects. Because there are no side effects and the value is discarded, this line has no effect.

Responding to the edit:

Firstly, it is important to distinguish calling another macro inside a macros body from emitting a call to another macro:

(defmacro some-macro []
  ...)

;; calls some-macro:
(defmacro example-1 []
  (some-macro))

;; emits a call to some-macro:
(defmacro example-2 []
  `(some-macro))

Secondly, in the case of calling functions and macros inside a macro's body, one must keep in mind what the relevant notions of runtime and compile time are:

functions called by a macro will be called at the macro expander's runtime, which is compile time from the point of view of user code;

macros called by a macro will be expanded when the macro body is compiled.

If a macro emits a call to another macro, the notions of runtime and compile time relevant to the emitted macro call will be the same as those relevant to the original macro call. If a macro calls another macro, they are shifted one step back, as it were.

To illustrate, let's consider a macro that delegates all its work to a helper function:

(defn emit-abc [abc-name [a b c]]
  `(def ~abc-name {:a ~a :b ~b :c ~c}))

(defmacro defabc [abc-name abc-vals]
  (emit-abc abc-name abc-vals))

From the REPL:

user> (defabc foo [1 2 3])
#'user/foo
user> foo
{:a 1, :c 3, :b 2}

If `emit-abc` were itself a macro, the above definition of `defabc` wouldn't even compile, because `emit-abc` would attempt to destructure the literal symbol `abc-vals`, throwing an `UnsupportedOperationException`.

Here's another example that makes it easier to explain what's happening:

(let [[a b c] [1 2 3]]
  (defabc foo [a b c]))

`defabc` receives the vector of the three literal symbols `a`, `b` and `c` as the second argument; it has no access to the runtime values `1`, `2` and `3`. It passes this exact vector of symbols to the function `emit-abc`, which is then able to reach into this vector and extract the symbols to produce the map `{:a a :b b :c c}`. This map becomes the expansion of the `defabc` call. At runtime `a`, `b` and `c` turn out to be bound to the values `1`, `2` and `three`, and so the map `{:a 1 :b 2 :c 3}` is produced.

Suppose we tried to write `emit-abc` as a macro with the same body (just changing `defn` to `defmacro` in its definition). Then we couldn't usefully call it from `defabc`, because we wouldn't have any way of conveying to it the actual values of the arguments to `defabc`. We could write

(emit-abc abc-name [(abc-vals 0) (abc-vals 1) (abc-vals 2)])

to make `defabc` compile, but this would end up emitting `abc-name` as the name of the Var being defined and include code for the vector literal `[a b c]` three times in the generated code. We could however emit a call to it:

`(emit-abc ~abc-name ~abc-vals)

This works as expected.

Problem

My puzzle is the following example: ``` (defmacro macro1 [x] (println x)) (defn func1 [x] (println x)) (defmacro macro2 [x] `(macro1 ~x) (func1 x)) (defmacro macro3 [x] (func1 x) `(macro1 ~x)) (println "macro2") (macro2 hello) (println "macro3") (macro3 hello) ``` Surprisingly, the output is: ``` macro2 hello macro3 hello hello ``` Why the output of macro2 and macro3 are different? In my understanding, all the calling of macro inside macro could be substituted with function (except for the reason of reuse). Anything wrong in my understanding? Thanks Michael for clarifying. My general question is how to choose between using function or macro inside macro for the purpose of manipulating the s-expression. I wonder whether they can be used exchangeably except that they're evaled at different phases. Another example: ``` (defn manipulate-func [x] (list + x 1)) (defmacro manipulate-macro [x] (list + x 1)) (defmacro macro1 [x y] [(manipulate-func x) `(manipulate-macro ~y)]) (println (clojure.walk/macroexpand-all '(macro1 (+ 1 2) (+ 3 4)))) ;; [(#<core$_PLUS_ clojure.core$_PLUS_@332b9f79> (+ 1 2) 1) (#<core$_PLUS_ clojure.core$_PLUS_@332b9f79> (+ 3 4) 1)] ```

Original source