On Thu, Apr 14, 2011 at 10:42 AM, Mark Rathwell <mark.rathw...@gmail.com> wrote: > > Actually, that doesn't seem to be the case, seems to have something to do > with the closure affecting macro expansion, but again, need someone smarter > to explain: > user> (defn plus-x [x] (fn [y] (+ x y))) > #'user/plus-x > user> (eval (mapper (plus-x 1) [1 2 3])) > ; Evaluation aborted. > user> (eval (mapper (fn [x] (+ 1 x)) [1 2 3])) > (2 3 4)
This is that weird bug/glitch/unsupported feature when an actual function object (as opposed to a symbol referring to a local or a var holding one) is eval'd. It seems that this works for non-closure fns but fails when the fn closes over a value from its context. I assume that eval of sexps with embedded function objects is not supported, and that it works even for some function objects is more or less accidental. Embed the quoted function code, e.g. (mapper `(partial + ~x) ...) rather than (mapper (partial + x) ...), or make a defn out of the function and call it by name, e.g. (defn foo ...) ... (mapper foo ...). Note that the former only works if x is something eval'able itself, such as a number or a string or something similar, or a Clojure data structure composed ultimately of same. If it is, or contains, some other kind of Java object, you've got trouble again. The problem with generic objects in eval is partially solvable: 1. If the sexp is constructed and then eval'd in the same session, a constant reference to the object could simply be embedded in the generated bytecode as a class constant of reference type. 2. If the code is being AOT compiled, and the object implements Serializable, it could be serialized as some sort of resource, and the AOT output could include a static initializer that loads that resource and stores a reference in a class constant. Currently, neither of the above is implemented. The case that would remain if they were would be: 3. The code is being AOT compiled and the object does not implement Serializable. That case subdivides as follows: 3a. The object cannot even in principle usefully be preserved across sessions or moved between JVMs, e.g. because it contains file handles or other native resources (ex.: FileInputStream). 3b. The object can in principle be preserved, and fairly simply; case 2 above would Just Work(tm) if you just slapped "implements Serializable" on the thing's class. 3c. The object can in principle be preserved, but not simply; e.g. WeakReference, which hooks into the GC; you'd need to first preserve the referent (if not null) and then a) load that and then b) construct a WeakReference to it in the target JVM instance. ReferenceQueues add more complication in that instance. 3c could reduce to 3b in the case of a proper writeObject/readResolve method pair. However, for Clojure to support case 3b requires some kind of heap introspection capability (likely involving native code) that allows it to directly copy the bytes of an object's in-memory representation. That prevents making 3c work via the writeObject/readResolve method, and would presumably not work in sandboxed JVMs. I doubt it's particularly practical to attempt to support case 3, just 1 and 2. -- You received this message because you are subscribed to the Google Groups "Clojure" group. To post to this group, send email to clojure@googlegroups.com Note that posts from new members are moderated - please be patient with your first post. To unsubscribe from this group, send email to clojure+unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/clojure?hl=en