released b.44 - fixes a major concurrency bug in the propagation algorithm (`m/memo`, m/stream, m/signal)
I read https://gist.github.com/dustingetz/d3fb5338b43ef86df5f97387f1d5e249#file-await_promise-clj.
it mentions the ambiguity
> Do you want to await the result of an already running promise
> or do you want to run the process of the promise when the task is run?
and the task await-promise return should be the first task? since p is not under control.
but what if I want the second kind of task?
the senario is I have third party lib provide many functions that return promise/future.
I want to wrap them in task, and get referential transparency, I can run the task multiple time to get multiple effects
(let [task (promise->task (third-party-f))]
(m/?
(m/? task) ;; run underlying effect
(m/? task) ;; run underlying effect again
))Here is an example with CompletableFuture
(defn from-cf-call [->cf]
(fn [s f]
(try (let [^CompletableFuture cf (->cf)]
(.whenComplete cf
(reify BiConsumer
(accept [_ r e]
(if (nil? e)
(s r) (f e)))))
#(.cancel cf true))
(catch Throwable e
(f e) #(do)))))
(defmacro from-cf [& body]
`(from-cf-call (fn [] ~@body)))The exact adapter logic may vary depending on the semantics of your future, especially how it behaves on cancellation