made with Findka

Refreshing namespaces breaks *data-readers*

12 June 2019

If you call `` 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
$ for f in $(find -type f); do echo $f:; cat $f; echo; done
(ns foo.core)

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

{foo/bar foo.core/foo-reader}

(ns user
  (:require [ :refer [refresh]]))

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

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

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

$ clj -e "(good)"
:reloading (user foo.core)
$ 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(
	at clojure.lang.AFn.invoke(
	at clojure.lang.Var.invoke(
	at clojure.lang.LispReader$CtorReader.readTagged(
	at clojure.lang.LispReader$CtorReader.invoke(
	at clojure.lang.LispReader$DispatchReader.invoke(
	at clojure.lang.RT.readString(
	at clojure.lang.RT.readString(
	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(
	at clojure.lang.Compiler.eval(
	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(
	at clojure.lang.Var.applyTo(
	at clojure.main.main(

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.

There's more where that came from if you subscribe to my newsletter.