Describe how the Rust compiler transforms an `async fn` into a `Future`. What is the role of the state machine?
Go & Rust interview question for Advanced practice.
Answer
When the Rust compiler encounters an async fn, it performs a significant transformation. It converts the entire function body into a state machine that implements the Future trait. This state machine has several states, corresponding to the different stages of the function's execution. Each .await point in the function becomes a potential suspension point, which translates to a state in the machine. All local variables that need to persist across an .await point are stored as fields within this generated state machine struct. When the Future is polled by a runtime: 1. The code runs until it hits an .await on an incomplete future. At this point, the state machine saves its current state (including all necessary local variables) and returns Poll::Pending. 2. When the awaited future is ready, the runtime polls the state machine's future again. 3. The state machine restores its saved state and resumes execution from where it left off. 4. This continues until the function reaches its end, at which point the state machine returns Poll::Ready(value), completing the Future.
Explanation
This compile-time transformation is what makes Rust's async implementation 'zero-cost'. You only pay for the complexity you use, without needing a heavy, mandatory runtime for the language itself.