Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
refreshing namespaces breaks *data-readers*

If you call clojure.tools.namespace.repl/refresh before requiring any namespaces referenced in data_readers.clj, then *data-readers* gets messed up somehow. The readers you define in data_readers.clj won't work even if you require their namespaces. For example:

$ find -type f
./src/foo/core.clj
./src/data_readers.clj
./src/user.clj
./deps.edn
$ for f in $(find -type f); do echo $f:; cat $f; echo; done
./src/foo/core.clj:
(ns foo.core)

(defn foo-reader [x]
  (Long/parseLong x))

./src/data_readers.clj:
{foo/bar foo.core/foo-reader}

./src/user.clj:
(ns user
  (:require [clojure.tools.namespace.repl :refer [refresh]]))

(defn good []
  (require 'foo.core)
  (read-string "#foo/bar \"123\"") ; works
  (refresh)
  (read-string "#foo/bar \"123\"")) ; still works

(defn bad []
  (refresh)
  (require 'foo.core)
  (read-string "#foo/bar \"123\"")) ; doesn't work

./deps.edn:
{:deps {org.clojure/tools.namespace {:mvn/version "0.2.11"}}}

$ clj -e "(good)"
:reloading (user foo.core)
123
$ clj -e "(bad)"
:reloading (user foo.core)
Exception in thread "main" java.lang.IllegalStateException: Attempting to call unbound fn: #'foo.core/foo-reader
	at clojure.lang.Var$Unbound.throwArity(Var.java:45)
	at clojure.lang.AFn.invoke(AFn.java:32)
	at clojure.lang.Var.invoke(Var.java:384)
	at clojure.lang.LispReader$CtorReader.readTagged(LispReader.java:1448)
	at clojure.lang.LispReader$CtorReader.invoke(LispReader.java:1427)
	at clojure.lang.LispReader$DispatchReader.invoke(LispReader.java:846)
	at clojure.lang.LispReader.read(LispReader.java:285)
	at clojure.lang.LispReader.read(LispReader.java:216)
	at clojure.lang.LispReader.read(LispReader.java:205)
	at clojure.lang.RT.readString(RT.java:1874)
	at clojure.lang.RT.readString(RT.java:1869)
	at clojure.core$read_string.invokeStatic(core.clj:3815)
	at clojure.core$read_string.invoke(core.clj:3805)
	at user$bad.invokeStatic(user.clj:13)
	at user$bad.invoke(user.clj:10)
	at user$eval535.invokeStatic(NO_SOURCE_FILE:1)
	at user$eval535.invoke(NO_SOURCE_FILE:1)
	at clojure.lang.Compiler.eval(Compiler.java:7176)
	at clojure.lang.Compiler.eval(Compiler.java:7131)
	at clojure.core$eval.invokeStatic(core.clj:3214)
	at clojure.main$eval_opt.invokeStatic(main.clj:465)
	at clojure.main$eval_opt.invoke(main.clj:459)
	at clojure.main$initialize.invokeStatic(main.clj:485)
	at clojure.main$null_opt.invokeStatic(main.clj:519)
	at clojure.main$null_opt.invoke(main.clj:516)
	at clojure.main$main.invokeStatic(main.clj:598)
	at clojure.main$main.doInvoke(main.clj:561)
	at clojure.lang.RestFn.applyTo(RestFn.java:137)
	at clojure.lang.Var.applyTo(Var.java:705)
	at clojure.main.main(main.java:37)

I'm not sure why this happens, but you can fix it by requiring any namespaces in data_readers.clj from your user.clj file (or whatever your repl entrypoint is). As long as you require them before the first call to refresh, they'll work.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.