On Sun, Dec 29, 2013 at 4:24 PM, larry google groups < lawrencecloj...@gmail.com> wrote:
> And here is where the greatest disappointment arrives: neither > future<http://clojuredocs.org/clojure_core/clojure.core/future> > nor promise <http://clojuredocs.org/clojure_core/clojure.core/promise> in > Clojure supports listening for completion/failure asynchronously. ... As > much as I love Clojure concurrency primitives like STM and agents, futures > feel a bit underdeveloped. Lack of event-driven, asynchronous callbacks > that are invoked whenever futures completes (notice that > add-watch<http://clojuredocs.org/clojure_core/clojure.core/add-watch> doesn't > work futures - and is still in alpha) greatly reduces the usefulness of a > future object. We can no longer: > > - map futures to transform result value asynchronously > - chain futures > - translate list of futures to future of list > - ...and much more, see how Akka does > it<http://nurkiewicz.blogspot.no/2013/02/javautilconcurrentfuture-basics.html> > and Guava to some > extent<http://nurkiewicz.blogspot.no/2013/02/advanced-listenablefuture-capabilities.html> > > That's a shame and since it's not a technical difficulty but only a > missing API, I hope to see support for completion listeners soon. > > > > So, I am curious if we will see support for completion listeners. Or is > there a feeling that stuff like core.async has addressed some of this and > nothing more is needed? > Well, core.async directly subsumes the entire functionality of promises. And adds watch capability: (let [c (chan)] ; instead of (promise) (go ; prefer thread if the long calculation is REALLY long (>! c (long calculation here)) ; instead of (future (deliver ...)) (close! c)) (let [d (go (let [x (<! c)] (println "Special delivery!" x) ; Watch! x))] (<!! d))) ; (instead of @c) The channel here is used just like a promise: the first go asynchronously does some calculation and delivers a result to it, then closes it, which results in behavior like a delivered promise, i.e. it can't be delivered to again. One could just use (<!! c) to grab the result (blocking until available), like @some-promise. The second go block shows one bit of added power: you can add an asynchronous watch for the result to appear. The go block takes it from c as soon as it's available, executes the watch (in this case a simple println), and then evaluates to the delivered value. Letting [d (go ...)] results in d being bound to a channel that will get this value pushed onto it (and then get closed) when the go block terminates, and (<!! d) blocks the main thread until this happens and then evaluates to the result. The one thing "missing" is that whereas you can @some-promise repeatedly to retrieve the value once it's delivered, you can't (<!! d) repeatedly without getting the delivered value once and then nils thereafter. But you could change it slightly to combine channels *with* promise: (let [c (chan)] (go (>! c (long calculation here)) (close! c)) (let [d (promise)] (go (let [x (<! c)] (println "Special delivery!" x) (deliver d x)))] @d)) Now d is a promise, but it's delivered by a go block that can also asynchronously watch for completion. But leaving d as a channel might be better. You can always put the result in another kind of container once it's delivered, and deref that repeatedly, and by leaving d a channel you can use alt! and timeout on this channel, for example, to add timeout behavior to your checking for delivery. Futures used locally can be "watched asynchronously" trivially: instead of (future (long calculation here)) you have (future (let [x (long calculation here)] (hey-x-got-finished! x) x)). The (hey-x-got-finished! x) call will take place in the future's thread. If you don't want it blocking the main thread (i.e. you want (hey-x-got-finished! x) able to run concurrently with whatever derefs the future, instead of the latter maybe being blocked longer) then you'd use (future (let [x (long calculation here)] (future (hey-x-got-finished! x)) x)). :) That deals with watching for completion. Watching for error is as easy with future: wrap a try ... catch around the body inside (future ...). With promise/core.async, you need the try block in the producer's code, whereas core.async lets you add completion watching at the consumer end as easily as at the producer. (Even to a normal promise generated by, say, code you can't change: just (let [c (thread @p)] ...) to turn promise p into channel c that will get @p pushed onto it when p is delivered; thread is used instead of go because a blocking job in a go is not recommended. Wrap the @p in something that will do something with its argument and return its argument to add a completion watch, for values of "do something" that can of course include spawning further async processes.) Futures you get passed from code you don't control (never heard of this happening, but I suppose it *could* happen) can be treated analogously to promises where you control only the consumer: for error checking you're SOL, but for completion watching you just wrap the deref in core.async's (thread ...). You can then spawn alarm processes from in there upon delivery, use the channel returned by (thread ...) in alts with timeout, use the channel in a go, just do a blocking take from it, and etc. -- -- You received this message because you are subscribed to the Google Groups "Clojure" group. To post to this group, send email to clojure@googlegroups.com Note that posts from new members are moderated - please be patient with your first post. To unsubscribe from this group, send email to clojure+unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/clojure?hl=en --- You received this message because you are subscribed to the Google Groups "Clojure" group. To unsubscribe from this group and stop receiving emails from it, send an email to clojure+unsubscr...@googlegroups.com. For more options, visit https://groups.google.com/groups/opt_out.