I wrote a little further up, but want to circle back as it’s less of an impulsive response given I’ve had a few days to think about it. There’s a lot going on in this thread and people are making good arguments in favour of every suggestion, however there are some specific suggestions which I strongly disagree with.
The first is the sigil form suggested. This is not specifically because I am against the idea, but because there is no obvious symbol to use for this form. The ? operator for something which could have failed is a logical choice. I have (so far) seen @, ! and # suggested in this thread and none of those make any sense with reference to async/await (at least to me). Regardless of if I’m missing something or not, the fact I might be represents that it will be very non-obvious to other users as well. If we do decide on sigils, it should only lead to yet another discussion of which symbol to use - it should not be chosen lightly. This extra overhead makes me against going this route (at least for now).
The other form is the field syntax. If you look at the code foo.await, it’s entirely non-obvious that this could take potentially forever to return. It’s too much of a deviation from what that syntax already represents. Conceptually, once someone has explained it to you, it’s not complicated. However I imagine most people will leave with a “that’s kinda gross” feeling. Do not forget that this is meant to be friendly for everyone, including newcomers and intermediates, not only those who are deeply involved with Rust. Not only do I feel it bad in this case, it would also set precedence for a pattern we might not want to continue with.
My initial response was to simply see the syntax of foo.await() come into play. I don’t see why async/await should be considered anything other than a function call from a developer perspective. The existing Future in the external crates literally has a foo.wait() which simply polls continuously. The biggest argument I’ve seen for this (disregarding arguments against postfix in general) is that it’s non-obvious that it’s doing something asynchronous. I understand this point of view, but would like to point out that just because you have a Future does not technically guarantee you’re doing something asynchronous.
I still agree with all of this, except that the extra couple of days have given me more time to reflect. As such, I have changed my mind to favour foo.await!(). It provides a very obvious syntax that can be used for similar features in future, as it’s familiar as it’s a combination of two existing things - macros and functions. Rather than caring that “it’s obvious it’s doing something asynchronous”, I now prefer this syntax because it’s obvious that it’s builtin, in the same way we all use println! rather than println. I believe that this syntax strikes a balance between familiarity and ergonomics, and has the added advantage that we’re also deciding the syntax for other features down the road. There are no new symbols required in the language, and there’s no real new concept that you have to learn to move to asynchronous programming.
I do still feel it’s a shame that we’re likely to go postfix rather than prefix, as I do like await foo(), but at this point I haven’t seen anything close to compelling for the prefix case which still solves the initial problem.