This duality of await
, behaving like a function call from the semantic outer perspective but not actually representing a call to an await
function, prompted me to prefer syntaxes that logically bound the await
to the call itself. The best syntax would be call-based and clearly associate the appearance of the async
keyword with the call itself, and none of its arguments (neither the future, nor any argument position in the call to allow for extensions to generator arguments later). I don’t think the macro variant does a good job of staying true to the function call aspect as a macro invocation is associated with a compile-time effect in my head and not a runtime one. My own proposal of future(await)
did a very bad job of the second aspect.
But, ultimately, there are different types of functions already: unsafe
and extern "C"
are not the same function types as normal ones. This makes it somewhat easier for me to accept await
as new function type, maybe surprisingly an inherent one, but still aligned to other features that exist in the language already. The parallel with unsafe fn
even goes as far as being callable within unsafe
code, whereas async
is callable in async code
! It’s not far from a new (imaginary) trait in the prelude:
trait Await {
type Output;
/// Implemented by compiler magic.
extern "await-call" fn r#await(self) -> Self::Output;
}
impl<F: Future> Await for F { type Output = F::Output; }