Rather than yet another thread pushing a new syntax, I would like to re-broach the topic of whether the initial plan of await actually needs fixing at all.
I have spent a lot of time looking at each solution proposed over the last few days, and have come to the conclusion that there are more negatives in them than leaving the syntax as it was originally planned (at least for the time being).
// previous, without ?
let value = await future;
let value = await my_async_function();
// previous, with ?
let value = (await future)?;
let value = (await my_async_function())?;
// new, without ?
let value = future.await;
let value = my_async_function().await;
// new, with ?
let value = future.await?;
let value = my_async_function().await?;
Based on the above, my conclusion is that there is a slight marginal improvement when using ? with the new syntax, which comes at the cost of a worsened syntax when not using ?. Given that itâs debatable whether there is improvement at all (see other threads for those arguments), I claim that the new syntax is actually not a net improvement and that we should therefore keep the original plan for the time being.
In order to enable the new syntax in future, I propose that although itâs dropped from the initial so-called âMVPâ implementation of async/await, it is instead introduced in a more general âPostfix Keywordâ feature in future when all other supported keywords also receive a postfix implementation. This should satisfy both those who want the new syntax and those who do not, and itâs actually more consistent because it will be like any other keyword and have both a postfix and non-postfix version.
I have written in more detail here for those interested; I wanted to keep it more concise for the forums.
Can you give more details about whyawait foo is materially better than foo.await? I see the notes that the former âmore familiarâ and âwell regardedâ, but thatâs a historical argument. Whatâs the argument that itâs intrinsically better for Rust?
As Iâm not qualified to truly speak on it, Iâll defer to the fact that it was originally the working syntax for the feature until the debate with ? came up. As such, there will be documentation on why this was chosen at that point in time by the language team.
Having said that, there are a few reasons I feel it better personally:
First off, I think the familiarity is an extremely good reason to keep that syntax. Rust already has a perceived high learning curve - changing syntax for (what will seem to be) little gain will be off-putting for newcomers. If I see (await foo())? as a newcomer, I know enough to decipher the inside of () and know that something asynchronous is happening in foo(). I donât know what ? does, but itâs a start. If I look at foo.await?, itâs pretty alien, particularly because itâs not obvious that there are two operators there.
Secondly, controversy is not something we want. The original syntax didnât have everyone up-in-arms on the forums trying to find alternatives, nor did it have people saying it was confusing/misleading/etc. Regardless of whether you agree with those arguments or not, itâs definitely better to avoid such a divided community. The lower amount of friction in the original syntax makes it favourable (to me).
Finally, thereâs more complexity with foo.await. Not necessarily in implementation, but weâre now setting precedence for postfix keywords which is something we probably donât want to rush. I donât think forcing that feature through to give us an arguable improvement in ? is necessary, especially given the hard timeline of the async/await feature. Without knowing the implementation, Iâd imagine it snowballs what weâre adding quite a lot.
At the eventual end of all this I would expect to have both forms. Iâm not arguing against foo.await itself, just against it right now. I believe that foo.await should not be considered any more urgent than foo.match, and that postfix keywords should have their own roadmap and be introduced in a consistent way across the board in one sweep. Naturally this would mean bringing foo.await into the language at that point in time.
Yes, it truly does. It has already been discussed and AFAIK the language team has already made the decision about fixing it. The only remaining issue to be settled is on the details how.
Note that withoutboats who made the current proposal personally prefers the await foo prefix syntax. But theyâve taken into account many other arguments and options on this to arrive at the current state, so itâs definitely not from lack of considering other options.
As far as Iâm aware this is not true. The RFC explicitly called the syntax out as an unresolved question because of the potential ordering issue. Where are you getting the impression that prefix-await was ever considered to be an actually proposed syntax? (It may have been used informally in discussion since a lot of people are familiar with it from C#/JS/Python/etc.)
Youâre right that Iâm talking more about how it has been presented in discussion. Even in the Paper document, that syntax is front and center as the thing to âfixâ - which suggests itâs already what we were going ahead with. If it was phrased as âwe need to decide on syntaxâ and it was simply another of the listed options, it would come across differently.
One of the listed options in the Paper document is âMandatory Delimitersâ, which is the same as (await foo)? from what I can see. So yes, âfixingâ it can mean accepting it as it is in prefix form.
The proposal from withoutboats makes good sense as a middle ground when considering the syntax alone. Given that itâs introducing the dependency of postfix keywords, Iâm not sure it should be associated with what has been labelled as an MVP of async/await. Of course, as stated above, adding the proposed syntax at a later date still makes sense.
I'll note it's hard to measure the controversy with a proposal because those in opposition to the proposal are always noisier than those who support it.
Personally I have not participated in the poll (and have tried to avoid getting drawn into opinion based discussion about the syntax) because I trust the language team to make a good decision. I know of a few others that are also basically abstaining from the discussion and are happy to go with whatever syntax is chosen. It seems likely that thereâs a significant number of people in a similar situation that are not going to appear in any sort of polling.
Of, course. In fact there is a much greater bias, the poll only reflects people actively reading this from. Most users of Rust do not fall into this category. Neither does anyone who will use Rust in the future but has not discovered it yet. It's always important to keep in mind that most of the users that will use the feature haven't found Rust yet.
That can be viewed as a further argument for favoring consistency within the language and with other languages, even if that is not favored by the experts and early adopters. However even in this poll there has been a strong preference in that direction.
Anything in the poll, though, is conditional on people having filled out the poll. If "Postfix await proposed for Rust" shows up on Reddit, the probability of someone who prefers prefix then going and filling out the poll is higher than the probability of someone who thinks "yeah, sounds fine" bothering to fill out the poll.
Maybe that is sometimes true, but looking back of the history of the poll (which you can see in my updates in the thread) The percentage of people who like or dislike the .await syntax hasn't change much. Both before and after the announcement it was not particularly widely liked.
The very first results from the poll had around 25% of people in favor of that syntax and 75% opposed, and it's less that 1% different from that now. So there hasn't been any clear change in response to the announcement.
Letâs just link âthe other pollâ which is more focused on the path to take right now. Currently, itâs âno opinionâ > "fut.await first" > "await fut first" > âneitherâ. (But also only 35 votes so far, so a very small sample size.)
I havenât really been following this topic, but this syntax looks totally alien to me. Is â.awaitâ a struct field? Some kind of method call without parentheses? Some kind of keyword with a â.â separator? This doesnât seem intuitive at all, it looks like some kind special case syntax thatâs different from Python and JavaScript or anything presently in Rust.
EDIT: Ok, found the longer thread.
I think I see what theyâre going for, but it seems like the original proposal has the benefit of working consistently with other languages while being less efficient to work with. Whereas the new proposal is inconsistent with other languages and Rustâs existing syntax patterns, but is more efficient to work with.
That being the case, Iâm not sure. Sorry, carry on I guessâŚ
"Historical" arguments matter. I'm really disappointed to see this concern dismissed in this way by you, another member of the lang team. Rust exists within a particular historical context, intended to benefit users who exist within that context, having knowledge, biases, expectations, needs, and so on all determined by that context. Imagining that you are designing a platonic language with "intrinsic" properties detached from its context is a deeply flawed, immature design philosophy.
This is much more important than just the syntax for the await operator; we can't design Rust as if we exist in a vacuum without historical context.
I agree that history and context matters, but they are not everything (not that you suggested that) and I do not read @scottmcm's comment as a dismissal of the concern as if it had no value at all. For example, in the RFC about reserving try { .. }, Scott makes such a historical argument well. Moreover, I read what Scott says as considering the history of Rust. In other words, "intrinsically" is not some sort of idealistic consideration in this context.
Certainly. A materialist philosophy rather than idealism seems prudent in all aspects of life and that includes language design. However, having a historical analysis is not necessarily the same as an argument by and for tradition. For example, taking history, context, and the user base into account, you may find that we want to do something different than what tradition might argue. To make progress, one also has to break with tradition in some cases.
So yes, learn from history, but don't necessarily repeat it.
Coming from a javascript / typescript background Iâm a little confused why the ? operator wouldnât be implied automatically by await prefix notation in the first place.
For example, in typescript an async function would look like this:
If either calls to foo or bar fail, the top level myFunc function rejects. This passes the error handling up automatically; much like the ? operator in rust does.
Is it because there is actually two Results in a rust future? One for the Future and one for the actual IO operation? If that were the case it seems like it would still be combined into one.