www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.announce - futures and related asynchronous combinators

reply Vlad Levenfeld <vlevenfeld gmail.com> writes:
https://github.com/evenex/future/

I've been having to do a lot of complicated async work lately 
(sometimes multithreaded, sometimes not), and I decided to 
abstract a some patterns out and unify them with a little bit of 
formalism borrowed from functional languages. I've aimed to keep 
things as simple as possible while providing a full spread of 
functionality. This has worked well for me under a variety of 
use-cases, but YMMV of course.

Anyway I've occasionally seen people on IRC asking about futures, 
so I thought I'd share and make this announcement.

This lib depends on another lib of mine (for tagged unions and 
related things) which might not appeal to some but if there is 
demand for futures sans dependencies I can always go back and 
manually inline some of the templates.

TL;DR:

   auto x = async!((y,z) => y + z)(1,2);
   x.await;
   assert(x.result.success = 3);
Mar 27 2016
next sibling parent reply Eugene Wissner <belka caraus.de> writes:
On Sunday, 27 March 2016 at 07:16:53 UTC, Vlad Levenfeld wrote:
 https://github.com/evenex/future/

 I've been having to do a lot of complicated async work lately 
 (sometimes multithreaded, sometimes not), and I decided to 
 abstract a some patterns out and unify them with a little bit 
 of formalism borrowed from functional languages. I've aimed to 
 keep things as simple as possible while providing a full spread 
 of functionality. This has worked well for me under a variety 
 of use-cases, but YMMV of course.

 Anyway I've occasionally seen people on IRC asking about 
 futures, so I thought I'd share and make this announcement.

 This lib depends on another lib of mine (for tagged unions and 
 related things) which might not appeal to some but if there is 
 demand for futures sans dependencies I can always go back and 
 manually inline some of the templates.

 TL;DR:

   auto x = async!((y,z) => y + z)(1,2);
   x.await;
   assert(x.result.success = 3);
Hi Vlad, Are you intend to open source other parts of your work? Can I ask what are you using for your async stuff: libasync, vibe, asynchronous or something self written?
Mar 27 2016
parent Vlad Levenfeld <vlevenfeld gmail.com> writes:
On Sunday, 27 March 2016 at 08:16:22 UTC, Eugene Wissner wrote:
 On Sunday, 27 March 2016 at 07:16:53 UTC, Vlad Levenfeld wrote:
 https://github.com/evenex/future/

 I've been having to do a lot of complicated async work lately 
 (sometimes multithreaded, sometimes not), and I decided to 
 abstract a some patterns out and unify them with a little bit 
 of formalism borrowed from functional languages. I've aimed to 
 keep things as simple as possible while providing a full 
 spread of functionality. This has worked well for me under a 
 variety of use-cases, but YMMV of course.

 Anyway I've occasionally seen people on IRC asking about 
 futures, so I thought I'd share and make this announcement.

 This lib depends on another lib of mine (for tagged unions and 
 related things) which might not appeal to some but if there is 
 demand for futures sans dependencies I can always go back and 
 manually inline some of the templates.

 TL;DR:

   auto x = async!((y,z) => y + z)(1,2);
   x.await;
   assert(x.result.success = 3);
Hi Vlad, Are you intend to open source other parts of your work? Can I ask what are you using for your async stuff: libasync, vibe, asynchronous or something self written?
For things like timers, event loops and networking in my current project I am using libasync. As for other parts of my work: I've been getting some good mileage out of a small set of generic primitives for operating on serial streams, I will probably pull them out and release them with some documentation soon.
Mar 27 2016
prev sibling parent reply maik klein <maikklein googlemail.com> writes:
On Sunday, 27 March 2016 at 07:16:53 UTC, Vlad Levenfeld wrote:
 https://github.com/evenex/future/

 I've been having to do a lot of complicated async work lately 
 (sometimes multithreaded, sometimes not), and I decided to 
 abstract a some patterns out and unify them with a little bit 
 of formalism borrowed from functional languages. I've aimed to 
 keep things as simple as possible while providing a full spread 
 of functionality. This has worked well for me under a variety 
 of use-cases, but YMMV of course.

 [...]
What happens when you spawn a future inside a future and call await? Will the 'outer' future be rescheduled?
Mar 27 2016
parent Vlad Levenfeld <vlevenfeld gmail.com> writes:
On Sunday, 27 March 2016 at 15:10:46 UTC, maik klein wrote:
 On Sunday, 27 March 2016 at 07:16:53 UTC, Vlad Levenfeld wrote:
 https://github.com/evenex/future/

 I've been having to do a lot of complicated async work lately 
 (sometimes multithreaded, sometimes not), and I decided to 
 abstract a some patterns out and unify them with a little bit 
 of formalism borrowed from functional languages. I've aimed to 
 keep things as simple as possible while providing a full 
 spread of functionality. This has worked well for me under a 
 variety of use-cases, but YMMV of course.

 [...]
What happens when you spawn a future inside a future and call await? Will the 'outer' future be rescheduled?
I think that you are asking about what happens if you call "async" from within another "async" call. If that's the case: Short answer: No rescheduling by default. The outer future is ready as soon as the inner future has been spawned. You would still have to await the inner future separately. If you are chaining "async" calls you will want to use "next" and/or "sync" to get the rescheduling behavior you want. Long answer: It depends on how you spawn the future. A future is a passive thing. All it does, by itself, is signify a value yet to be computed. There is no constraint on how the future is to be fulfilled. You could create a future manually with "pending", in which case calling "await" on it would block forever (because the future never has "fulfill" called on it). What a function like "async!f" does is to create a future with an implied promise to fulfill that future from another thread. Let's suppose "f", internally, calls "async" to return a Future!A. Then "async!f" spawns a Future!(Future!A). The outer future is ready once "f" returns, and the inner future will be ready once the async operation launched by "f" completes. To await the final result, you might call "await.result.await", which quickly becomes awkward. To avoid this awkwardness, you should use "sync" to flatten nested futures, or "next" to automatically flatten the futures as you chain them. For example: async!f : Future!(Future!A) async!f.sync : Future!A async!({}).next!f : Future!A If you're familiar with functional design patterns, Future is a monad with "next" as bind, "sync" as join, and "pending!A.fulfill(a)" as return. If not, just remember - "sync" removes a layer of nesting, and "next" chains future calls without nesting them. Hope that helped!
Mar 27 2016