Welcome! Please see the About page for a little more info on how this works.

+1 vote
in Printing by

Is the print-method implementation for functions intended to produce valid edn syntax? In some cases, it does not:

user> (require '[org.httpkit.server :as http])
user> (def s (http/run-server (fn [req] {:status 200}) {}))
user> (prn s)

Symbol names can't start with a number, so clojure.lang.AFunction/1 causes a parse error when read back:

user> (clojure.edn/read-string (prn-str s))
Execution error at user/eval7394 (REPL:68).
Invalid token: clojure.lang.AFunction/1

Is this the expected behavior? If so, printing and re-reading data structures that may contain fns can fail.

1 Answer

0 votes
selected by
Best answer

Yes, this is the expected behavior. Functions are not serializable in this way and edn has no representation for function instances.

I guess the number creating an unreadable tagged literal could maybe be considered a problem.
Thanks, Alex. It's the unreadable tagged literal I was curious about. Handling tagged literals is a separate topic; but I'd think print-method should produce syntactically valid edn.
Generally, print-method does NOT guarantee to produce syntactically valid edn (there are many ways to violate that assumption), and are not even guaranteed to print Clojure data. Whether to support edn printing or print/read roundtrip in a stronger way is an item under consideration for work in 1.11.
That would be excellent to see in 1.11. In case it aids thinking around that work, here's a  detail that eluded me when I posted the original question:

The unreadable tagged literal does not seem to be generated by clojure itself. cider-nrepl adds print-method implementations for certain object types, including clojure.lang.AFunction. This is ordinarily helpful; but the global nature of multimethods means this can bite (or at least confuse) you. I was surprised to see pr-str produce a different result when I tested this in a vanilla repl. A way of printing data structures that is consistent (unaffected by the environment) and guaranteed readable (by the edn reader) would be a useful feature indeed.
Ah, right, I didn't realize this was the print function added by cider.

The whole printing infrastructure is designed to be user modifiable so I think making that independent of the environment is a non-goal.
Oh definitely -- user-modifiable is key. But explicit scope helps with the principle of least astonishment.

For example, the opts arg to edn/read makes user-defined behavior clear and simple to reason about. In contrast, with print-method, I didn't modify the default behavior, but something else did -- globally. It had a good reason. But it was surprising and non-trivial to track down.