functionserializationclojureedn

How can I serialize functions at runtime in Clojure?


Is there a way to serialize functions at runtime in Clojure? I'd like to be able to send stateless (but not pure) functions over the wire in a serialized format (probably edn, but I'm open to anything).


For example...

If I run prn-str on a function, I don't get what I expected/wanted.

user=> (def fn1 (fn [x] (* x 2)))
#'user/fn1
user=> (def data {:test 1 :key "value"})
#'user/data
user=> (defn fn2 [x] (* x 2))
#'user/fn2
user=> (prn-str fn1)
"#object[user$fn1 0x28b9c6e2 \"user$fn1@28b9c6e2\"]\n"
user=> (prn-str data)
"{:test 1, :key \"value\"}\n"
user=> (prn-str fn2)
"#object[user$fn2 0x206c48f5 \"user$fn2@206c48f5\"]\n"
user=> 

I would have wanted/expected something like this:

user=> (prn-str fn2)
"(fn [x] (* x 2))\n"

or, maybe,

user=> (prn-str fn2)
"(defn fn2 [x] (* x 2))\n"

Solution

  • At some point it ceases to be Clojure, so the expectation that we can arbitrarily round trip from source to machine instructions and back is a little bit off.

    We should be able to serialize a function to a byte array and send that across the wire though. I suspect you'd need to grab the function's java.lang.Class object and then pass that through a java.lang.instrument.ClassFileTransformer to get the bytes. Once you have those you can pass them through to the friendly java.lang.ClassLoader on the remote jvm.