Reputation: 73
If I evaluate
(def ^:macro my-defn1 #'defn)
a macro named 'my-defn1' is defined, which I can use just like 'defn'.
However, if I evaluate instead
(if true
(def ^:macro my-defn2 #'defn))
the var for 'my-defn2' doesn't have the :macro metadata set and I can't use it as a macro, even though the 'def' form is equal to the previous case.
Here is the complete code (http://cljbin.com/paste/52322ba5e4b0fa645e7f9243):
(def ^:macro my-defn1 #'defn)
(if true
(def ^:macro my-defn2 #'defn))
(println (meta #'my-defn1)) ; => contains :macro
(println (meta #'my-defn2)) ; => doesn't contain :macro!
(my-defn1 hello1 []
(println "hello 1"))
(hello1) ; => prints "hello 1"
(my-defn2 hello2 [] ; => CompilerException: Unable to resolve
(println "hello 2")) ; symbol: hello2 in this context
What makes the behaviour different?
Upvotes: 3
Views: 188
Reputation: 17773
Clojure's def cannot really be conditionally applied. The documentation for def is IMO insufficiently strong on that part. It's not just bad style, it can cause all kinds of subtle issues.
You should only use def at the top-level, or in a do
or let
form at the top-level. Conditionally applying def will result in the functionality being split up in something like declare
and a subsequent conditional def
, but not always in the way that you'd expect/like.
You might be better off using def at the top level here and then conditionally using alter-var-root
. Or use (def my-var (if .. .. ..))
. Think about why you'd ever want to have a global definition "disappear".
Upvotes: 1