3 ms·
But what's the difference between an async function returning int, and a function returning `impl Future<int>`? If there's no difference why do we need the asyn
by ridiculous_fish 5y ago
But what's the difference between an async function returning int, and a function returning `impl Future<int>`? If there's no difference why do we need the async keyword?
Other parts of the language are conditioned on the return type. For example the ? operator only works if the return type is Option or Result. It seems like `await` could inspect the return type in the same way.
- kibwen 5y ago> But what's the difference between an async function returning int, and a function returning `impl Future<int>`? If there's no difference why do we need the async keyword? No difference, but while the feature was being explored early users found it simpler if they didn't need to think about lifetimes on the returned future. Sometimes sugar is just sugar; same reason that `for` loops exist instead of just using `while`.
- steveklabnik 5y agoYou can't await inside of a function returning impl Future<Int>. (You can inside an async block inside one, but there you go with language-level support again.) You need the collaboration with the compiler to make it all work well. And that means keywords and language-level infrastructure. We tried no sugar, and it was rough: http://aturon.github.io/tech/2018/04/24/async-borrowing/ http://aturon.github.io/tech/2018/04/24/async-borrowing/ (And a proc macro didn't work out either)
- Rusky 5y agoThe 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.