LoadWasher() | RunWasher() | LoadDryer() | RunDryer() | IronClothes()
CleanKitchen()
where `|` is piping the output of one operation into the next one (as per *nix shell). The two lines are independent and so can be scheduled according to resources available.Doing so makes the inherent dependencies trivially clear. It doesn't matter which are "long" running and which aren't: it's not possible to run the washer until it's been loaded. Using async/await conflates two things:
1. What's "long" running, for some definition of "long" (--> make it async)
2. What's dependent on what (await)
--
EDIT: fix formatting & added missing "RunDryer()" step
Then wrap it in a try/catch or pattern match the result to handle the various errors different errors...
No, the point is you don't _need_ async. At least not as a language primitive. Instead, one expresses directly where the data dependencies lie. If an operation in a pipeline blocks, the runtime is at liberty to switch to another task. That already happens today, whether in language runtimes (e.g. Node) or the underlying OS. I don't need to tell the runtime "this operation might block". It already knows.
Instead, we've explicitly defined intent: when `RunWasher()` finishes, `LoadDryer()`. It doesn't matter if the washer takes one micro second or one hour; I can't load the dryer until it's done.
>Then wrap it in a try/catch or pattern match the result to handle the various errors different errors...
True, error handling is missing. But then it's not in the parent example either. The requirements aren't fundamentally different in either case.
If you replace the machines with people, it makes much more sense for the function definition to define what is and isn't synchronous. If you have to do all the chores yourself, just call the functions synchronously. If you have family members you can delegate some work to, you can call the functions asynchronously and wait for them to complete while you're doing your own work (or twiddling your thumbs).
Elixir allows you to do this very cleanly. https://hexdocs.pm/elixir/Task.html#content
If I do what I've always done in rust, which in use threads, I get lovely easy parallelization. Async only seems useful when your program doesn't do anything non trivial, but just dispatches to other things, as any one function that takes a long time blocks all other async functions until completion?
- What is the best approach to encapsulate blocking I/O in future-rs? — https://stackoverflow.com/q/41932137/155423
I'd rather dirty the signatures of blocking/synchronous methods then of the rest.