Welcome! Please see the About page for a little more info on how this works.

0 votes
in Clojure by
edited by

Suppose I'm trying to write a macro that can create a list of :tag metadata attributes (ex: Java type hints) for a given vector of symbols. Consider the following REPL session:

(def ^String x nil)
(def ^Integer y nil)
(def ^Long z nil)
(defmacro all-tags [items]
   (vec (for [item items]
      `(:tag (meta (resolve (quote ~item)))))))

; this works fine
(all-tags [x y z])
[java.lang.String java.lang.Integer java.lang.Long]

; however, if I instead have a symbol that refers to this list, it fails
(def myargs [x y z])
(all-tags myargs)
Syntax error macroexpanding all-tags at (form-init2442452721395147632.clj:1:1).
Don't know how to create ISeq from: clojure.lang.Symbol

How can I rewrite the all-tags macro to handle the second case, such that it returns the same result as the first case?

1 Answer

+2 votes
selected by
Best answer

So, when you do

(def myargs [x y z])

x, y, and z are already evaluated --- myargs is [nil nil nil] --- and so getting the symbol/var metadata is going to be tough.

Here is a macro-free version that does something similar:

> (def ^String x nil)
> (def ^Integer y nil)
> (def ^Long z nil)
> x
> y
> z
> (defn all-tags [items]
    (map (comp :tag meta resolve) items))
> (all-tags '[x y z])
(java.lang.String java.lang.Integer java.lang.Long)
> (def myargs '[x y z])
> (all-tags myargs)
(java.lang.String java.lang.Integer java.lang.Long)
Thank you; greatly appreciate the sample code!
For sure! I learned something too. (: