how to be notified when a Future is realized?

315 views
Skip to first unread message

lawrence...@gmail.com

unread,
Aug 2, 2017, 5:09:04 PM8/2/17
to Clojure
I stumbled across this old post by Tomasz Nurkiewicz:


He writes: 

"And here is where the greatest disappointment arrives: neither future nor promise in Clojure supports listening for completion/failure asynchronously. The API is pretty much equivalent to very limited java.util.concurrent.Future<T>. We can create futurecancel it, check whether it is realized? (resolved) and block waiting for a value. Just like Future<T> in Java, as a matter of fact the result of future function even implements java.util.concurrent.Future<T>. 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 doesn't work futures - and is still in alpha) greatly reduces the usefulness of a future object. "

That was written in 2013. I think since then the community has found other ways to achieve the same goals? I'm curious what patterns have become common? Would it be correct to say that for most of the use cases where one would otherwise want a notification of completion on a Future, people nowadays instead use something like core.async or a library such as Manifold? 








Justin Smith

unread,
Aug 2, 2017, 5:19:43 PM8/2/17
to Clojure
for this sort of logic, I use core.async go blocks containing a call to core.async/thread, doing some other operation asynchronously with the value in the channel it returns

(go
  (let [result (<! (thread (do-something))]
    (do-something-else result)))

this is non-blocking and runs in core.async's thread pool and state machine, and when I have multiple conditions to coordinate on, the kind of code core.async lets me write is much more readable compared to callback nesting

I also have my own version of thread which attempts support cancellation while also handling the attached channel properly, but I haven't done the work to vet it as generally usable

--
You received this message because you are subscribed to the Google
Groups "Clojure" group.
To post to this group, send email to clo...@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+u...@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+u...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Leonardo Borges

unread,
Aug 2, 2017, 5:39:15 PM8/2/17
to clojure
I created imminent for this purpose : https://github.com/leonardoborges/imminent

It's based on Java's completable futures. I've written an extensive README in the repo. Have a look, it might be useful for your case. 

Cheers, 
Leonardo Borges 


On 3 Aug. 2017 7:19 am, "Justin Smith" <noise...@gmail.com> wrote:
for this sort of logic, I use core.async go blocks containing a call to core.async/thread, doing some other operation asynchronously with the value in the channel it returns

(go
  (let [result (<! (thread (do-something))]
    (do-something-else result)))

this is non-blocking and runs in core.async's thread pool and state machine, and when I have multiple conditions to coordinate on, the kind of code core.async lets me write is much more readable compared to callback nesting

I also have my own version of thread which attempts support cancellation while also handling the attached channel properly, but I haven't done the work to vet it as generally usable
On Wed, Aug 2, 2017 at 2:09 PM <lawrence...@gmail.com> wrote:
I stumbled across this old post by Tomasz Nurkiewicz:


He writes: 

"And here is where the greatest disappointment arrives: neither future nor promise in Clojure supports listening for completion/failure asynchronously. The API is pretty much equivalent to very limited java.util.concurrent.Future<T>. We can create futurecancel it, check whether it is realized? (resolved) and block waiting for a value. Just like Future<T> in Java, as a matter of fact the result of future function even implements java.util.concurrent.Future<T>. 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 doesn't work futures - and is still in alpha) greatly reduces the usefulness of a future object. "

That was written in 2013. I think since then the community has found other ways to achieve the same goals? I'm curious what patterns have become common? Would it be correct to say that for most of the use cases where one would otherwise want a notification of completion on a Future, people nowadays instead use something like core.async or a library such as Manifold? 








--
You received this message because you are subscribed to the Google
Groups "Clojure" group.
To post to this group, send email to clo...@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

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+unsubscribe@googlegroups.com.

For more options, visit https://groups.google.com/d/optout.

--
You received this message because you are subscribed to the Google
Groups "Clojure" group.
To post to this group, send email to clo...@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

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+unsubscribe@googlegroups.com.

Alf

unread,
Aug 3, 2017, 2:28:01 AM8/3/17
to Clojure
Imminent looks pretty good, I was not aware of it.

We use Manifold, because we use Aleph, both of which we think are great. Manifold also has a nice integration with core.async.

Cheers,
Alf

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+u...@googlegroups.com.

For more options, visit https://groups.google.com/d/optout.

--
You received this message because you are subscribed to the Google
Groups "Clojure" group.
To post to this group, send email to clo...@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

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+u...@googlegroups.com.

James Gatannah

unread,
Aug 4, 2017, 2:05:27 AM8/4/17
to Clojure
Just to be fair: I didn't dig into the other posts in that series to try to figure out where he was going.

So I could be completely and totally off-base on this.

My first reaction was "This is the point behind core.async."

My second reaction was "Why not just use an atom and (add-watch)?"

Then I read his disclaimer that add-watch was still in alpha. March 2013? According to https://jafingerhut.github.io/clojure-benchmarks-results/Clojure-version-history.html, clojure was up to 1.5 at that point.

Yeah, OK. I can see that still being an alpha feature at that point.

But my third (and, for now, final) reaction was "Why not just supply a callback?"

Think 1 is (hopefully) going to finish at some point in time in the future.

It's nice (in theory) to be able to say "Stop processing here until some other thread toggles this flag."

And then just resume processing when that flag is toggled.

I've spent the past couple of years fighting with variations on this. We keep running into weird issues where t, u, v, x, y, and z run practically instantaneously, but w had this weird hiccup that blocked everything for 3 seconds. And no one can explain why.

I think every book I've ever read about implementing scheme is built around this idea. You set up a Kontinuation to restore the call stack and resume control when some condition is met.

But, honestly, is it really that complex to just hand over a callback?

Sure, that callback might do something with core.async or manifold (my experience with both has been great!), or trigger off a bunch of fireworks. Or stick the latest response message onto a queue for something else to process later.

But the part that calls that should neither know/care. It got a new message that gives it a reason to trigger something. It's a big, nasty, ugly, thing that's going to involve a bunch of side-effects. Trigger them and be done.

It scares me that I just wrote that.

But I think I'm in pretty good company here.

1. Get some message that tells you side-effects need to happen
2. Build a seq of side-effects that have to happen
3. Call something like (reduce) across that seq to actually make them happen

The actual mechanism behind it all (promise, future, async/chan, manifold/stream, etc) is an implementation detail.
Reply all
Reply to author
Forward
0 new messages