Skip to content

Instantly share code, notes, and snippets.

What would you like to do?
clojure.test.check.random + GraalVM native-image randomization issue


Clone: $ git clone && cd test.check

Make main class:

echo "(ns foo (:gen-class)) (require '[clojure.test.check.random :as r]) (defn -main [& args] (prn (r/rand-long (r/make-random))))" > src/main/clojure/foo.clj

Make classes dir: mkdir -p classes

AOT compile:

$ clojure -Sdeps '{:deps {org.clojure/clojure {:mvn/version "1.10.2-alpha1"}}}' -e "(require 'foo) (compile 'foo) (compile 'clojure.test.check.random)"

Run on JVM, observe that random works:

$ java -cp classes:$(clojure -Spath) foo
$ java -cp classes:$(clojure -Spath) foo

Compile with GraalVM native-image:

$ $GRAALVM_HOME/bin/native-image foo --no-fallback --no-server --report-unsupported-elements-at-runtime --initialize-at-build-time -cp $(clojure -Sdeps '{:deps {org.clojure/clojure {:mvn/version "1.10.2-alpha1"}} :paths ["classes"]}' -Spath)

Run binary, observe that random doesn't work:

$ ./foo
$ ./foo


(def next-rng
  "Returns a random-number generator. Successive calls should return
  independent results."
  (let [a (atom (delay (r/make-java-util-splittable-random (System/currentTimeMillis))))
        (proxy [ThreadLocal] []
          (initialValue []
            (first (r/split (swap! a #(second (r/split (force %))))))))]
    (fn []
      (let [rng (.get thread-local)
            [rng1 rng2] (r/split rng)]
        (.set thread-local rng2)

(defn make-random
  "Given an optional Long seed, returns an object that satisfies the
  IRandom protocol."
  ([] (next-rng))
  ([seed] (r/make-java-util-splittable-random seed)))

With this code patched (either directly or through alter-var-root the GraalVM binary will work correctly.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment