futures and related asynchronous combinators

Vlad Levenfeld via Digitalmars-d-announce digitalmars-d-announce at puremagic.com
Sun Mar 27 12:50:04 PDT 2016


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!


More information about the Digitalmars-d-announce mailing list