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:

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!

Reply via email to