Problem Statement
The function clojure.core/deref
throws a hard-to-decipher ClassCastException
when given an object that's not an instance of clojure.lang.IDeref
or java.util.concurrent.Future
. In my experience on-boarding new Clojure users (at my job and in my open source projects), this comes up and can be quite confusing as it doesn't point to anything obvious in the code. Even with the stack trace, it just points to deref-future
's definition (instead of a specific line within the function body), which further confuses.
Discussion
On Slack, I proposed changing the implementation of deref
to be something like (cond (instance? clojure.lang.IDeref ref) ... (instance? java.util.concurrent.Future ref) ... :else (throw (IllegalArgumentException (str ref " cannot be deref'd as it is of type " (class ref) "."))
.
Sean Corfield brought up that such a fix would cost performance for all non-IDeref uses of deref
, which I acknowledged but find acceptable.
Repro:
user=> (def a {})
#'user/a
user=> @a
Execution error (ClassCastException) at user/eval22861 (REPL:0).
class clojure.lang.PersistentArrayMap cannot be cast to class java.util.concurrent.Future (clojure.lang.PersistentArrayMap is in unnamed module of loader 'app'; java.util.concurrent.Future is in module java.base of loader 'bootstrap')
user=> (pst)
ClassCastException class clojure.lang.PersistentArrayMap cannot be cast to class java.util.concurrent.Future (clojure.lang.PersistentArrayMap is in unnamed module of loader 'app'; java.util.concurrent.Future is in module java.base of loader 'bootstrap')
clojure.core/deref-future (core.clj:2315)
clojure.core/deref-future (core.clj:2315)
clojure.core/deref (core.clj:2338)
clojure.core/deref (core.clj:2323)
user/eval22863 (NO_SOURCE_FILE:0)
user/eval22863 (NO_SOURCE_FILE:-1)
clojure.lang.Compiler.eval (Compiler.java:7194)
clojure.lang.Compiler.eval (Compiler.java:7149)
clojure.core/eval (core.clj:3215)
clojure.core/eval (core.clj:3211)
clojure.main/repl/read-eval-print--9206/fn--9209 (main.clj:437)
clojure.main/repl/read-eval-print--9206 (main.clj:437)