UncleBob
UncleBob

Reputation: 1391

passing arguments into syntax-quoted macros

While hunting a bug in one of our clojure modules, I stumbled upon a syntax-quoted macro to which somebody passed arguments. After some debugging I realised that this doesn't work as intended, as the arguments do not have the values they should have.

The below is a minimal representation of the situation encountered in the actual code. It should illustrate the point pretty well:

(def testargs {:arg1 "foo"
               :arg2 "bar"})

(defmacro argtest
  [arg1 arg2]
  `(str ~@(arg1 testargs) " " ~@(arg2 testargs))

This works nicely as expected if I call the code like this:

(argtest :arg1 :arg2)
=> "foo bar"

However, if the two arguments are passed in as variables, it does not work so well:

(let [arg1 :arg1 arg2 :arg2]
  (argtest arg1 arg2))
=> " "

To get to the bottom of the problem, I changed the macro as follows and ran the tests again:

(defmacro argtest2
  [arg1 arg2]
  (str arg1 " " arg2))

(argtest2 :arg1 :arg2)
=> ":arg1 :arg2"

(let [argument1 :arg1 argument2 :arg2]
  (argtest2 argument1 argument2))
=> "argument1 argument2"

As you can see, what happens is that the variable names are passed as values. How can I avoid this? Should I just try to rewrite the code to avoid a macro, or can I somehow make this work?

An obvious solution would of course be something like this:

(defmacro argtest
  [arg1 arg2]
  `(str (~arg1 ~testargs) " " (~arg2 ~testargs)))

But since the output of the macro is inserted into another code block before evaluation, this is not possible.

Upvotes: 0

Views: 75

Answers (1)

Josh
Josh

Reputation: 4806

Forms are not evaluated before being passed to macros as they are with functions. Without broader context or knowing what you're trying to do, the simplest solution would be to use a function, as you seem to want the arguments evaluated in all cases, though maybe I'm oversimplifying your problem:

(defn argtest [arg1 arg2]
  (str (arg1 testargs) " " (arg2 testargs)))

Upvotes: 2

Related Questions