3 ms·
The difference between `await` and `?` is that the former completely transforms the entire function body containing it, while `?` just conditionally returns fro
by Rusky 5y ago
The difference between `await` and `?` is that the former completely transforms the entire function body containing it, while `?` just conditionally returns from it. (There's less of a difference to the caller of the function, where both `async` and `impl Future` give you a `Future` object.)
A normal function returning `impl Future` has normal synchronous control flow, cannot ever use `await`, and then eventually returns a value whose type implements the Future trait. You can't just return an int, because ints don't implement `Future`- you have to return something that is `poll`-able.
On the other hand, an `async fn` merely looks like it has normal synchronous control flow, with some `await`s sprinkled in. But when you call it, none of that code runs- instead it immediately constructs and returns a value (of anonymous type, similar to a closure) whose type implements `Future`. The code written in the body has its control flow ripped apart at `await` points, much like a CPS transform, and it goes in the `poll` method of that value's `Future` impl.
It's technically possible that the language could have been designed the way you describe- if an `await` is present, that transformation happens, otherwise it doesn't. But because of the nature of the `await` operator, this is much messier than `?`. For example, when the transformation happens, you need to be able to return an `int`, and when it doesn't you must return an `impl Future`, unlike `?` where you always have to return a `Result` or `Option` regardless of your use of `?`. And you wouldn't be able to tell at a glance whether the function body runs immediately when it's called, or whether it waits for the Future to be `poll`ed. Plus, the language also has `async { .. }` blocks that do the same transformation in an expression context, so it's kind of nice to be consistent with that.