Is there a way to set a watch on a future so that it triggers a callback when it is done?
something like this?
> (def a (future (Thread/sleep 1000) \"
For very simple cases: If you dont want to block and dont care about the result just add the callback in the future definition.
(future (a-taking-time-computation) (the-callback))
If you care about the result use comp with the call back
(future (the-callback (a-taking-time-computation)))
or
(future (-> input a-taking-time-computation callback))
Semantically speaking the java equivalent code would be:
final MyCallBack callbackObj = new MyCallBack();
new Thread() {
public void run() {
a-taking-time-computation();
callbackObj.call();
}
}.start()
For complex cases you may want to look:
https://github.com/ztellman/manifold
https://github.com/clojure/core.async
Instead of adding additional time with Thread/Sleep
, I'm leveraging on the fact that @future-ref
for any reference to the future will wait until the future is done.
(defn wait-for
[futures-to-complete]
(every? #(@%) futures-to-complete))
I found this thread on google which looks interesting:
https://groups.google.com/forum/?fromgroups=#!topic/clojure-dev/7BKQi9nWwAw
http://dev.clojure.org/display/design/Promises
https://github.com/stuartsierra/cljque/blob/master/src/cljque/promises.clj
You can start another task that watches the future and then runs the function. In this case I'll just use another future. Which wraps up nicely into a when-done function:
user=> (defn when-done [future-to-watch function-to-call]
(future (function-to-call @future-to-watch)))
user=> (def meaning-of-the-universe
(let [f (future (Thread/sleep 10000) 42)]
(when-done f #(println "future available and the answer is:" %))
f))
#'user/meaning-of-the-universe
... waiting ...
user=> future available and the answer is: 42
user=> @meaning-of-the-universe
42
An extension to the accepted answer
please note the following caveat:
with the above when-done
implementation the callback will not be invoked
if the future is cancelled.
That is
(do
(def f0 (future (Thread/sleep 1000)))
(when-done f0 (fn [e] (println "THEN=>" e)))
(Thread/sleep 500)
(future-cancel f0))
will not print because the deref call on the cancelled future will raise an exception.
If you need callbacks to happen i suggest:
(defn then
"Run a future waiting on another, and invoke
the callback with the exit value if the future completes,
or invoke the callback with no args if the future is cancelled"
[fut cb]
(future
(try
(cb @fut)
(catch java.util.concurrent.CancellationException e
(cb)))))
So now this will print:
(do
(def f0 (future (Thread/sleep 1000)))
(then f0 (fn
([] (println "CANCELLED"))
([e] (println "THEN=>" e))))
(Thread/sleep 500)
(future-cancel f0))