Functions with closures seem to break when used with eval.
(eval {:fn (let [x "foo"] (fn [] "x"))})
;=> {:fn #<user$eval14716$fn__14717 user$eval14716$fn__14717@1ddd735>}
(eval {:fn (let [x "foo"] (fn [] x))})
;=> IllegalArgumentException No matching ctor found for class user$eval14740$fn__14741
; clojure.lang.Reflector.invokeConstructor (Reflector.java:166)
I don’t really know enough about Clojure (or closure) to know if this is a bug or something which intentionally isn’t allowed – can anyone shed some light on this?
Edit: Just to be clear, I’m talking specifically about the way eval handles function objects. AFAIK eval is actually designed to work with java objects, including functions; the example given on the clojure website – (eval (list + 1 2 3)) – passes a function object into eval.
Cloure’s
evaldoes not perfectly support function objects. It’s not necessarily even closures that cause the problem.For example, this did not work in Clojure 1.0.0:
But this did:
The first example got fixed. The following also works:
But the following still does not work:
I can’t pin it down to a single line in the compiler, but it’s something about how literal objects (clojure.lang.Compiler$ObjExpr I think) get handled by
evalin different contexts: e.g. at the “top” of an expression versus inside another data structure.In general, I think, you cannot rely on being able to
evalfunction objects in Clojure, regardless of whether or not they are closures. It happens to work for some simple examples, mostly to simplify the explanation of things like(eval (list + 1 2)). Macros should always return literal source code as data structures, not compiled functions.