Given a Clojure function which references a class, if that class has a static field with an initializer which fails when run, the function will fail to compile because the compiler (needlessly) runs the initializer even if the respective field is not accessed. Notably, this does not happen when storing the class in a var and then referencing it through that instead (see workaround below). Could the compiler support the direct reference here?
Reproducer
(The following code is also available at https://github.com/bevuta/clojure-fn-compilation-issue-repro)
deps.edn
:
{:deps {io.netty/netty-codec {:mvn/version "4.1.108.Final"}}}
src/repro/fail.clj
:
(ns repro.fail
(:import io.netty.handler.codec.compression.BrotliOptions))
(defn bar []
BrotliOptions)
(defn -main [& args]
(prn (bar)))
Here, the bar
function references the io.netty.handler.codec.compression.BrotliOptions
class. That class has a package-private static field named DEFAULT
with an initializer. That initializer depends on a class which is provided by an optional third-party library. However, even though bar
never references that field, the initializer gets run and fails because that library is not present.
Run it like this:
$ clojure -M -m repro.fail
Execution error (ClassNotFoundException) at jdk.internal.loader.BuiltinClassLoader/loadClass (BuiltinClassLoader.java:641).
com.aayushatharva.brotli4j.encoder.Encoder$Parameters
Workaround
The issue can be worked around by putting the class value into a separate def
and using that in the function instead:
src/repro/ok.clj
:
(ns repro.ok
(:import io.netty.handler.codec.compression.BrotliOptions))
(def foo BrotliOptions)
(defn bar []
foo)
(defn -main [& args]
(prn (bar)))
Run it like this:
$ clojure -M -m repro.ok
io.netty.handler.codec.compression.BrotliOptions
Relevance
The issue was encountered in the context of https://github.com/clj-commons/aleph/issues/703