graalvm

Discuss GraalVM related topics. Use clojure 1.10.2 or newer for all new projects. Contribute to https://github.com/clj-easy/graal-docs and https://github.com/BrunoBonacci/graalvm-clojure. GraalVM slack: https://www.graalvm.org/slack-invitation/.
borkdude 2020-08-29T18:52:10.051600Z

I'm doing an experiment of integrating clojure.spec into babashka, together with generators. I'm running into a slight problem: the generated results aren't random, due to this line being evaluated at compile time, I think: https://github.com/clojure/test.check/blob/7e7c2116fa721211e8f5642a249e4a0f327445f4/src/main/clojure/clojure/test/check/random.clj#L175 One solution is to fork clojure.test.check, unless someone may have a better idea... I could also try alter-var-root

borkdude 2020-08-29T18:55:06.052200Z

I think a solution would be to wrap the global random object in a delay

lread 2020-08-29T19:06:13.055400Z

Huh, interesting. Sorry no better ideas here but I suppose a fork could become a PR for test.check.

borkdude 2020-08-29T19:07:22.055900Z

Trying alter-var-root first. If it works out, a proper PR could be made

borkdude 2020-08-29T19:08:44.056300Z

Seem to work :)

borkdude@DESKTOP-JN2UNTV ~/dev/babashka (spec) $ ./bb "(require '[clojure.spec.alpha :as s] '[clojure.spec.gen.alpha :as gen]) (s/def ::foo int?) (gen/generate (s/gen ::foo))"
-2
borkdude@DESKTOP-JN2UNTV ~/dev/babashka (spec) $ ./bb "(require '[clojure.spec.alpha :as s] '[clojure.spec.gen.alpha :as gen]) (s/def ::foo int?) (gen/generate (s/gen ::foo))"
-11621
borkdude@DESKTOP-JN2UNTV ~/dev/babashka (spec) $ ./bb "(require '[clojure.spec.alpha :as s] '[clojure.spec.gen.alpha :as gen]) (s/def ::foo int?) (gen/generate (s/gen ::foo))"
-13

borkdude 2020-08-29T19:09:09.056600Z

The patch:

(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))))
        thread-local
        (proxy [ThreadLocal] []
          (initialValue []
            (delay
              (first (r/split (swap! a #(second (r/split (deref %)))))))))]
    (fn []
      (let [rng @(.get thread-local)
            [rng1 rng2] (r/split rng)]
        (.set thread-local (delay rng2))
        rng1))))

(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)))

(alter-var-root #'r/next-rng (constantly next-rng))
(alter-var-root #'r/make-random (constantly make-random))

borkdude 2020-08-29T19:11:50.056900Z

@alexmiller Let me know if a PR is in order

borkdude 2020-08-29T19:28:21.057400Z

I guess we could use clojure.core/force to work with normal values after the initial delay has been forced.

borkdude 2020-08-29T20:58:23.058400Z

So this works with GraalVM as well:

(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))))
        thread-local
        (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)
        rng1))))

(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)))

borkdude 2020-08-29T20:59:18.059500Z

but wrapping the entire body of next-rng into a delay and then calling (@next-rng) in make-random doesn't (I got: can't case Delay into IFn with GraalVM compiled)