How Programming Languages Model Asynchronous Program Flow 40 When using Rust, you can see the same transformation happening with the function signature when you write something such as this: async fn run()-> () {... } The function wraps the return object, and instead of returning the type (), it returns a Future with an output type of (): Fn run()-> impl Future<Output = ()> Syntactically, Rust's futures 0. 1 was a lot like the promise example we just showed, and the Rust futures we use today have a lot in common with how async /await works in Java Script.. This way of rewriting what look like normal functions and code into something else has a lot of benefits, but it's not without its drawbacks. As with any stackless coroutine implementation, full pre-emption can be hard, or impossible, to implement. These functions have to yield at specific points, and there is no way to suspend execution in the middle of a stack frame in contrast to fibers/green threads. Some level of pre-emption is possible by having the runtime or compiler insert pre-emption points at every function call, for example, but it's not the same as being able to pre-empt a task at any point during its execution. Pre-emption points Pre-emption points can be thought of as inserting code that calls into the scheduler and asks it if it wishes to pre-empt the task. These points can be inserted by the compiler or the library you use before every new function call for example. Furthermore, you need compiler support to make the most out of it. Languages that have metaprogramming abilities (such as macros) can emulate much of the same, but this will still not be as seamless as it will when the compiler is aware of these special async tasks. Debugging is another area where care must be taken when implementing futures/promises. Since the code is re-written as state machines (or generators), you won't have the same stack traces as you do with normal functions. Usually, you can assume that the caller of a function is what precedes it both in the stack and in the program flow. For futures and promises, it might be the runtime that calls the function that progresses the state machine, so there might not be a good backtrace you can use to see what happened before calling the function that failed. There are ways to work around this, but most of them will incur some overhead. Advantages Y ou can write code and model programs the same way you normally would No context switching