eval'ing records and some anonymous functions

50 views
Skip to first unread message

David McNeil

unread,
Apr 15, 2011, 8:58:57 AM4/15/11
to Clojure Dev
I have found that records and some anonymous functions don't eval to
themselves:

(defrecord Foo [a])
(eval (Foo. 100))
;; -> {:a 100}
;; I expected this to eval to: #:user.Foo{:a 100}

(let [f (partial + 1)]
(eval `(map ~f [1 2])))
;; -> No matching ctor found for class clojure.core$partial...
;; I expected this to eval to: (2 3)
#:user.Foo{:a 100}

This seems to be inconsistent with how most other objects are behave.
My question is whether this behavior is by design or whether it should
be changed to make them eval to themselves?

Thank you.
-David

(I posted these questions yesterday on the Clojure list but did not
receive definitive responses. Apologies to those who subscribe to both
lists:
http://groups.google.com/group/clojure/browse_thread/thread/2384ca6497321350
http://groups.google.com/group/clojure/browse_thread/thread/389f137cb1a62026)

Stuart Sierra

unread,
Apr 15, 2011, 9:41:33 AM4/15/11
to cloju...@googlegroups.com
Since Clojure doesn't have an interpreter, `eval` is really "compile into a function and invoke that function."  The Clojure compiler is designed to take a restricted set of literals and data structures and turn them into executable code.

Records will probably be added to the set of things the compiler understands when they become first-class objects: http://dev.clojure.org/display/design/defrecord+improvements

I think it's unlikely that the Compiler will ever be able to understand compiled functions.

-Stuart Sierra
clojure.com

David McNeil

unread,
Apr 15, 2011, 9:58:40 AM4/15/11
to Clojure Dev
Stuart - Thank you for the response. The part about records makes
sense to me. However, I don't really understand the issue with
functions. For example, this works:

(let [f #(+ 1 %)]
(eval `(map ~f [1 2])))
;; -> (2 3)

Maybe I am wrong, but it seems to me that this is evaling the function
#(+ 1 %).

Thanks.

-David

Kevin Downey

unread,
Apr 15, 2011, 11:09:53 AM4/15/11
to cloju...@googlegroups.com, David McNeil
could be a classloader issue, the class for the fn returned by
(partial ...) was most likely generated by AOT compilation when your
clojure jar was built, while the class for the fn #(+ 1 %) is
generated on the fly there .

> --
> You received this message because you are subscribed to the Google Groups "Clojure Dev" group.
> To post to this group, send email to cloju...@googlegroups.com.
> To unsubscribe from this group, send email to clojure-dev...@googlegroups.com.
> For more options, visit this group at http://groups.google.com/group/clojure-dev?hl=en.
>
>

--
And what is good, Phaedrus,
And what is not good—
Need we ask anyone to tell us these things?

Kevin Downey

unread,
Apr 15, 2011, 11:14:25 AM4/15/11
to cloju...@googlegroups.com, David McNeil
no, I guess it can't be a classloader thing given that is has the
class in hand, just can't construct it

Kevin Downey

unread,
Apr 15, 2011, 11:23:58 AM4/15/11
to cloju...@googlegroups.com, David McNeil
https://gist.github.com/921874

it's a closed over thing, the constructor of the fn returned by (comp
inc inc) takes two arguments (closes over the passed in arguments)
while the class for (fn [x] (inc x)) has a no arg constructor.
apparently you can only eval fn objects that aren't closures.

Stuart Sierra

unread,
Apr 15, 2011, 2:06:39 PM4/15/11
to cloju...@googlegroups.com
The compiler will accept compiled functions in a few special cases, mostly to make it easier to write macros without triggering the dreaded "cannot embed object in code" error. But in general you cannot rely on the compiler understanding non-literal objects.

-S

David McNeil

unread,
Apr 15, 2011, 2:11:50 PM4/15/11
to Clojure Dev
Kevin - Thank you. That helps me understand what is going on and which
functions I can expect to eval.

-David
Reply all
Reply to author
Forward
0 new messages