Copy C# async/await. (async ...) establishes a block, within which (await a-future-or-promise) will relinquish control, wiring up a state machine representing the rest of the block to the notification of the future/promise. The async block itself returns a promise.
This will require notifying futures/promises. Relevant reading:
It will also require an ambient thread pool.
This proposal has been coded up and the result is available here: https://github.com/relevance/clojure-async-blocks
There are 4 major steps to this implementation:
1) The expression inside the state-machine macro is transversed
2) For each node an instruction for a virtual machine is recorded
3) These instructions (in a SSA style block format) are analyzed to find temporary variables
4) The instructions are emitted as a state machine.
5) The state machine is wrapped by functions that pack and unpack tasks
The output of the state machine macro is a function that takes an old state and produces a new state. Thus these state machines are immutable, and side affect free (assuming the code in them is also side-effect free).
Work to be done:
- Think about try/catch/finally, doesn't work at the moment
- Don't overload the deref value, instead we will use await to deref listenable futures
- Remove generator code, it could be confusing to new users
- Decide on a good future/promise library