Fork me on GitHub
#code-reviews
<
2021-09-07
>
noisesmith18:09:32

on the JVM where there is no real stack storage of data, "store the state of the function" would mean reifying the stack pointer (entrypoint) and call stack (what you return to) into something you can execute later by interpreting it, and storing all scoped heap references in a way you can later restore.

noisesmith18:09:01

this is expensive, because as far as I know the only way to have a resumable continuation on the jvm is to use an interpreter (IOW use a reified stack for your code, and put an interpreter in the actual stack)

noisesmith18:09:24

I'm basing what I'm saying on my understanding of the jvm - it can't do goto past method boundaries which is a pre-requisite for non-interpreted continuations

noisesmith18:09:37

I'd be interested in being proved wrong actually

noisesmith18:09:46

oh! you mean loom the jvm project

noisesmith18:09:58

yes, that's awesome and up and coming, it totally changes what the jvm can do

noisesmith18:09:06

I was thinking of loom the graph library lol

noisesmith18:09:17

right, so continuations are coming... eventually

emccue22:09:38

well for "fun" stuff i don't see a reason to wait to use the ea builds

emccue22:09:47

rust people build companies on nightly

Russell Mull22:09:44

I'm a "Rust person" building a company on nightly. I wish I wasn't, but there's some embedded stuff that just can't be done on stable yet.

emccue22:09:26

(import java.lang.Continuation)
=> java.lang.Continuation
(import java.lang.ContinuationScope)
=> java.lang.ContinuationScope
(ContinuationScope. "scope")
=> #object[java.lang.ContinuationScope 0x4356af7c "scope"]
(def default-scope (ContinuationScope. "scope"))
=> #'user/default-scope
(Continuation. default-scope (fn []
                               (println "A")
                               (Continuation/yield default-scope)
                               (println "B")))
=> #object[java.lang.Continuation 0x3a99c9b2 "java.lang.Continuation@3a99c9b2 scope: scope"]
(def cont (Continuation. default-scope (fn []
                                         (println "A")
                                         (Continuation/yield default-scope)
                                         (println "B"))))
=> #'user/cont
(.run cont)
A
=> nil
(.run cont)
B
=> nil
(.run cont)
Execution error (IllegalStateException) at java.lang.Continuation/run (Continuation.java:286).
Continuation terminated

emccue22:09:08

(defn generator [f]
  (let [last-val (volatile! nil)
        scope (ContinuationScope. "generator")
        continuation (Continuation. scope (fn []
                                            (f (fn [v]
                                                 (vreset! last-val v)
                                                 (Continuation/yield scope)))))]
    (reify Iterator 
      (hasNext [_]
        (not (.isDone continuation)))
      (next [_]
        (.run continuation)
        @last-val))))
=> #'user/generator
(def gen (generator 
           (fn [yield]
             (doseq [x (range 10)]
               (yield x)))))
=> #'user/gen
(iterator-seq gen)
=> (0 1 2 3 4 5 6 7 8 9 9)

emccue22:09:02

its a start

emccue22:09:58

(defn generator [f]
  (let [no-yield (Object.)
        last-val (volatile! no-yield)
        scope (ContinuationScope. "generator")
        continuation (Continuation. scope (fn []
                                            (f (fn [v]
                                                 (vreset! last-val v)
                                                 (Continuation/yield scope)))))]
    (reify Iterator 
      (hasNext [_]
        (and (not (.isDone continuation))
             (do (.run continuation)
                 (not= @last-val no-yield))))
      (next [_]
        (when (and (not (.isDone continuation)) (= @last-val no-yield))
          (.run continuation))
        (let [val @last-val]
          (vreset! last-val no-yield)
          val)))))
=> #'user/generator
(def gen (generator 
           (fn [yield]
             (doseq [x (range 10)]
               (yield x)))))
=> #'user/gen
(iterator-seq gen)
=> (1 2 3 4 5 6 7 8 9)