Actually, one simple way to use core.async to asynchronously watch a future
or a promise, or *any* other blocking-derefable thingy, for delivery, is
just to throw a (thread (do-something-with @thingy)) in your code
somewhere. The thread will block until the thingy is ready, and then do
whatever. Meanwhile your usual code can just @thingy like it would have
anyway somewhere, without its behavior there being changed.

This can be done anywhere the thingy is visible. What can't be done with
any of these (including core.async used natively) is to catch errors
without being able to put (or amend) a try block into the producer end of
things. This suggests that anything where consumers might want notification
of failure should employ a separate error channel (core.async) or out of
band values (future, promise, core.async) produced in a try block. For
example (future (try (/ a b) (catch ArithmeticException _ :error))) where
the consumer can look for :error instead of a number when derefing (in this
case, this would be caused by the edge case b = 0).



On Sun, Dec 29, 2013 at 5:01 PM, Cedric Greevey <cgree...@gmail.com> wrote:

> 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.

Reply via email to