Matthew H
Matthew H

Reputation: 5879

Clojure: read-string on functions

Is there a way to use the reader with function values, e.g:

(read-string (pr-str +))

RuntimeException Unreadable form clojure.lang.Util.runtimeException (Util.java:219)

?

Upvotes: 2

Views: 1094

Answers (2)

user2263578
user2263578

Reputation: 215

If you only need the name, can you just send the symbol with (name '+).

But generally speaking, it is a bad idea to use clojure read, if you want to read it back, as clojure's reader might execute some code in the process. Maybe have a look at the edn reader : clojure.edn/read-string

But maybe you just need to convert the string back to a symbol, in which case the (symbol name) function would be enough.

Upvotes: 0

juan.facorro
juan.facorro

Reputation: 9920

As you might already know the output for (pr-str +) is not valid Clojure code that the reader can parse: "#<core$_PLUS_ clojure.core$_PLUS_@ff4805>". The output for function values when using the functions pr, prn, println and such, is intentionally wrapped around the #< reader macro that dispatches to the UnreadableReader, which throws the exception you are seeing.

For the example you provided you can use the print-dup function that works for basic serialization:

(defn string-fn [f]
  (let [w    (java.io.StringWriter.)]
    (print-dup f w)
    (str w)))

(let [plus (read-string (string-fn +))]
  (plus 1 2))

The serialization done for the + function is actually generating the call to the class' constructor:

#=(clojure.core$_PLUS_. )

This only works of course if the class is already compiled in the Clojure environment where you are reading the string. If you serialized an anonymous function, saving it to a file and then reading it back in, when running a new REPL session, it will most likely not work since the class name for each anonymous function is different and depends on Clojure internals.

For arbitrary functions things get a lot more complicated. Sharing the source code might not even be enough, the function could rely on the usage of any number of other functions or vars that only exist in the source environment. If this is what you are thinking of doing, maybe considering other approaches to the problem you are trying to solve, will eliminate the need to serialize the value of arbitrary functions.

Hope it helps,

Upvotes: 3

Related Questions