On Wed, May 4, 2011 at 8:01 PM, Ken Wesson <[email protected]> wrote:
> Note that instantiating the class with 4 gives us an add-4-to function
> instead of the original add-3-to function here. To actually convert
> that particular closure into code that reproduces it, the array of
> constructor arguments needs to be [{} 3]. (I'm not sure what the map
> argument is used for, but it seems to work when left empty, though not
> when omitted entirely.
I did some more experimenting and the map attaches as metadata to the closure:
user=> (def q (.newInstance (first (.getConstructors (.getClass
(fn-maker3 2 1)))) (into-array Object [{:foo 1} 3 4])))
#'user/q
user=> (q 10)
43
user=> (meta q)
{:foo 1}
There is also a second constructor for a closure that doesn't take a
map. But it comes second in the sequence returned by .getConstructors.
So you can use (second (.getConstructors ...)) with just the closures.
Note that the fn-maker3 above was defined with:
(defn fn-maker3 [x y] (fn [z] (+ (* z x) y)))
and
user=> ((fn-maker3 3 4) 10)
34
so it looks like the order of the constructor arguments can be
rearranged from what you might expect given how the closure was
defined. That wouldn't stop a clever compiler extension knowing the
order needed (as it decided that order in the first place), saving
them into the closure somehow (e.g. as metadata: {:recreate-args [4
3]}), and converting a closure into the code to recreate it (e.g.
`(.newInstance
(first (.getConstructors (class-for-name ~(.getName (.getClass closure)))))
(into-array Object (quote ~(cons (meta closure) (:recreate-args
(meta closure))))))
seems like it would evaluate to the required code, given the
:recreate-args metadata, and it would preserve the metadata too).
And since a non-closure also has two constructors -- besides the
no-argument one, one accepting just a metadata map -- the above should
in fact work to externalize any function object for reconstruction
later (in any running session that has the function's class available)
as long as the closed-over values (and the metadata) don't contain
anything non-externalizable. In fact, if closure constructors only
assoced the :recreate-args key into the closure's metadata
automatically as an additional final step you could wrap the above in
#=(eval ...) and use it to define print-dup for AFn.
--
You received this message because you are subscribed to the Google
Groups "Clojure" group.
To post to this group, send email to [email protected]
Note that posts from new members are moderated - please be patient with your
first post.
To unsubscribe from this group, send email to
[email protected]
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en