Two following examples of using a function in a macro result in evaluations without errors.
(defmacro works []
(let [f (fn [] 1)]
`(~f)))
(works)
;; =&
See this example that does also throw the exception:
(defmacro does-also-not-work []
(let [x 4
f (fn [] x)]
`(~f)))
Just like the result of constantly
, but unlike your first two examples, f
here is a closure. Apparently, closures created during macro-expansion time do not persist.
Take a look at clojure.lang.Compiler.ObjExpr#emitValue(). Any instance objects which appear directly in code (or generated code, in the case of macro-expansion results) must either:
print-dup
defined for their type, in which case the compiler emits object instantiation via round-tripping through the reader.Function objects do have a print-dup
implementation, but it constructs read-eval forms which only call the 0-argument version of the function class constructor:
(print-dup (fn [] 1) *out*)
;; #=(user$eval24491$fn__24492. )
(let [x 1] (print-dup (fn [] x) *out*))
;; #=(user$eval24497$fn__24498. )
Clojure closures are implemented via function-classes which accept their closed-over variable values as constructor arguments. Hence:
(let [f (fn [] 1)] (eval `(~f)))
;; 1
(let [x 1, f (fn [] x)] (eval `(~f)))
;; IllegalArgumentException No matching ctor found ...
So now you know, and know why to avoid directly inserting function objects into generated code, even when it "works."