A lazy future is one where no work happens before it’s polled the first time.
This will come up a lot if you read about futures in Rust, and since our own Future trait is based on that exact same model, the same question will arise here. The simple answer to this question is no!
There is nothing that forces leaf futures, such as the one we wrote here, to be lazy. We could have sent the HTTP request when we called the Http::get function if we wanted to. If you think about it, if we did just that, it would have caused a potentially big change that would impact how we achieve concurrency in our program.
The way it works now is that someone has to call poll at least one time to actually send the request. The consequence is that whoever calls poll on this future will have to call poll on many futures to kick off the operation if they want them to run concurrently.
If we kicked off the operation immediately when the future was created, you could create many futures and they would all run concurrently even though you polled them to completion one by one. If you poll them to completion one by one in the current design, the futures would not progress concurrently. Let that sink in for a moment.
Languages such as JavaScript start the operation when the coroutine is created, so there is no “one way” to do this. Every time you encounter a coroutine implementation, you should find out whether they’re lazy or eager since this impacts how you program with them.
Even though we could make our future eager in this case, we really shouldn’t. Since programmers in Rust expect futures to be lazy, they might depend on nothing happening before you call poll on them, and there may be unexpected side effects if the futures you write behave differently.
Now, when you read that Rust’s futures are always lazy, a claim that I see very often, it refers to the compiler-generated state machines resulting from using async/await. As we’ll see later, when your async functions are rewritten by the compiler, they’re constructed in a way so that nothing you write in the body of an async function will execute before the first call to Future::poll.
Okay, so we’ve covered the Future trait and the leaf future we named HttpGetFuture. The next step is to create a task that we can stop and resume at predefined points.