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

+3 votes
in Clojure by

Placing this form in a user namespace top-level:

(set! *default-data-reader-fn* tagged-literal)

leads to the following error when starting a REPL (with Clojure 1.11.1):

Exception in thread "main" Syntax error macroexpanding at (user.clj:9:1).
	at clojure.lang.Compiler.load(Compiler.java:7665)
	at clojure.lang.RT.loadResourceScript(RT.java:381)
	at clojure.lang.RT.loadResourceScript(RT.java:368)
	at clojure.lang.RT.maybeLoadResourceScript(RT.java:364)
	at clojure.lang.RT.doInit(RT.java:486)
	at clojure.lang.RT.init(RT.java:467)
	at clojure.main.main(main.java:38)
Caused by: java.lang.IllegalStateException: Can't change/establish root binding of: *default-data-reader-fn* with set
	at clojure.lang.Var.set(Var.java:226)
	at user$eval148.invokeStatic(user.clj:13)
	at user$eval148.invoke(user.clj:13)
	at clojure.lang.Compiler.eval(Compiler.java:7194)
	at clojure.lang.Compiler.load(Compiler.java:7653)
	... 6 more

Evaluating the same form after the REPL has started up works fine, though.

Further note that placing this form in the user top-level instead works fine:

(alter-var-root #'*default-data-reader-fn* (constantly tagged-literal))

Why does set! not work here? If there is a good reason for this, I suggest to update https://clojure.org/reference/reader#_default_data_reader_function to mention it.

1 Answer

+2 votes
selected by
Best answer

Dynamic vars need a root binding before they can be set! and there isn't one by default. For other similar configuration vars you might be used to doing this with, the repl itself is setting root bindings around the repl which makes this possible (see https://github.com/clojure/clojure/blob/master/src/clj/clojure/main.clj#L82-L99).

What I would really like to do is make tagged-literal the default default-data-reader-fn, and it would then have a root binding, and you would be able to set! it. I thought we had a ticket for this, but I couldn't find it, so I created one for that here: https://clojure.atlassian.net/browse/CLJ-2800

As a stop-gap, we could bind `*default-data-reader-fn*` to `nil`. That would at least solve this specific problem with no backwards compatibility issues while allowing y'all to think about issues that might arise from making `tagged-literal` the default.