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

+2 votes
in Compiler by
edited by

Reporting this as an example of a particularly cryptic error message. Admittedly not the most common thing, but when doing REPL-driven dev with code that uses primitive type tags it can happen.

The issue here as I understand it is that IFn contains a few hundred interfaces with some permutation of primitive input and output types, with names like LLO and ODOL. Functions that call this are compiled to call the primitive interface to avoid boxing,rather than the generic IFn. If the function is then redefined without or with different primitive tags, then the compiled calling code is no longer calling the right interface.

(defn foo ^long [^long x]
  x)

(defn bar []
  (+ (foo 3) (foo 4)))

(bar)

(defn foo [x] x)

(bar) ;;=> throws: class my.ns$foo cannot be cast to class  clojure.lang.IFn$LL

1 Answer

0 votes
by

It might be useful for the compiler to give a warning when a var is redefined such that it loses a primitive interface.

We could still detect these changes without compiler changes like this:

Clojure 1.12.5
user=> (defn f ^long [^long a] a)
#'user/f
user=> (add-watch #'f ::undo-prim (fn [_ _ old new] (when (and (instance? clojure.lang.IFn$LL old) (not (instance? clojure.lang.IFn$LL new))) (println "WARNING: removed clojure.lang.IFn$LL from f"))))
#'user/f
user=> (defn f [a] a)
WARNING: removed clojure.lang.IFn$LL from f
#'user/f
...