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

0 votes
in Clojure by

When an imported class is used as a value, the emitted bytecode uses {{RT.classForName}} to obtain the Class object, causing the class to be loaded and static initializers to be executed. This is different from when (link: http://docs.oracle.com/javase/specs/jls/se8/html/jls-12.html#jls-12.4.1 text: Java calls static initializers) and makes it more difficult to use clojure with code that depend on the Java semantics.

Some code has static initializers that can only execute in a certain environment. A prime example is JavaFX, where many JavaFX classes require the JavaFX platform to be started before any static initializers can run.

Consider this code:

(import 'javafx.scene.control.Cell)

(defn f [] Cell)

It currently can't be compiled and executed (for example with "{{clj example.clj}}" using clojure-1.9.0beta2) failing with a {{CompilerException java.lang.ExceptionInInitializerError}}, with the root cause "Toolkit not initialized". This use of {{Cell}} as the return value of {{f}} causes the class to be loaded and initialised.

Modify ObjExpr.emitValue to emit a call to {{RT.classForNameNonLoading}} instead of {{RT.classForName}} when the value being emitted is a Class.


Prior art
The {{import}} form previously was changed to similarly not load the class ((link: https://dev.clojure.org/jira/browse/CLJ-1315 text: CLJ-1315)) and (link: https://dev.clojure.org/jira/browse/CLJ-1743 text: CLJ-1743) attempts to address similar issues where Clojure differs from the Java semantics.

2 Answers

0 votes

Comment made by: ragge

Added patch.

0 votes
Reference: https://clojure.atlassian.net/browse/CLJ-2250 (reported by ragge)