# A final proposal for await syntax

**URL:** <https://internals.rust-lang.org/t/a-final-proposal-for-await-syntax/10021>\
**Category:** language design\
**Created:** [May 6, 2019, 2:36pm UTC](https://internals.rust-lang.org/t/a-final-proposal-for-await-syntax/10021 "2019-05-06T14:36:19Z")\
**Posts on this page:** 1\
**Showing post:** 256

<div class="post-metadata">

**Author:** ![theduke](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/theduke/32/2782_2.png) [@theduke](https://internals.rust-lang.org/u/theduke)\
**Post date:** [May 16, 2019, 5:01pm UTC](https://internals.rust-lang.org/t/a-final-proposal-for-await-syntax/10021/256 "2019-05-16T17:01:18Z")

</div>

> [@nikomatsakis](#):
>
> First, I’d be curious if you are able to point to the code in question (is it public?).

It is not, unfortunately, and it is quite a complicated code base and system, but I'll try to present a simplified but relatively faithful reproduction.

It looked something like this:

```rust
async fn execute(ctx: Context, input: InputValue) -> Result<Value, Error> {
  let input_a_and_b = ctx.get(input.x).build()?;

  // Step A.
  let future_a = async_action1(input_a_and_b.clone());

  let input_b = ctx
    .get(input.y)
    .build()
    .await?;
  let (flag, value_b) = match input_b {
    Enum::A(a) => {
        let modified_a = a
         .map(|x| x.modify())
         .unwrap_or(compute_other_value());
        let (flag, input_3) = async_action2(&ctx, modified).await?;

        // Step B.
        let output_b = async_action3( input_a_and_b, input_3, async_action2(..).await? )
            .await?  
            .method()
            .await;
        (flag, output_b)
     },
    Enum::B => {
      (false, Ok(None))
    },
  };
  
  let future_c = async_action4(flag);
  
  // Step C.
  let output = futures_preview::join!( future_a, future_c);
  match output { 
    // Nothing relevant for this example.
    // ...
  }
}

```

The context for this code is that it fetches some data, schedules processing in a few systems, and waits for some results. It's complicated by the fact that some part of the scheduling happens in bridged C++ code.

**Step A** Constructs a future which, during executing, at some point increments a counter. Note that due to Rust future semantics, future\_a does not start executing until step C.

**Step B** First fetches some flag which is needed for `future_c` and then calls `async_action3`. The last await at step B is the bug.

**Step C** joins on the two futures.

The bug is a subtle ordering issue which resulted in the `execute` method never finishing. `async_action3` runs some foreign code that waits until a counter is incremented, which happens during execution of `future_a`. (note they share some common input). It then schedules some processing, and returns an acknowledgement with a id.

Correct code would, instead of `await` ing at Step B, would have either done `join!(a, b, c)` or first the `join!(a,c)` and then await on the future from Step B.

This also wouldn't have happened in other `async/await` languages since they start executing immediately, but this is unrelated and just something you have to learn when adopting Rust.

This took me ... a long time to find. ( the real code is also has quite a bit more going on)

Now there are all kinds of ways this could have been prevented, like abstracting the interdependent code into a separate function.

It could also be argued that this bug could easily happen in any case and that the syntax isn't really a differentiator here, and that `.await` vs `@ await`, `|> await` or prefix await wouldn't have made a difference. I could understand that argument.

I guess for me it's partly the fact that appending `.await` is just so easy to do during in normal code flow that it doesn't provide a mental breakpoint.

With prefix await, you either have to know that you want to `await ` when starting to write an expression, or you have to recognize the need for it, backtrack to the start and insert the await. Personally this definitely causes me to re-evaluate the code and re-consider the await.

Some other construct like postfix pipelining **could** also provide a similar benefit if it's more associated with control flow. `@ await` is really not much harder to type than `.await`. It is a lot noisier though when reading it again! It is also clearly a distinct concept from field access. ( I probably read over the function above dozens of times before figuring out the issue)

This ties into your other question.

> I’d like to drill a bit into why it is important for it to stand out in git diffs.

Suspending can have a big impact on how code executes, especially so in Rust because futures need to be actively polled to make progress, **which makes ordering your suspension points correctly much more important than in , say JS or Python.**

The only way to draw your attention to a `.await` is syntax highlighting. It's really quite easy to skip over it in longer call chains, or in nested expressions (like the inline `.await` in my Step B).

To me, relying on syntax highlighting to recognize control flow is definitely a detriment. Plenty of contexts have no syntax highlighting, like some code review systems, git diff, or chat clients. It's also a language design question, should control flow be easily recognizable?

An interesting comparison here is prefix await, because in theory the same could apply there. I think this is improved by two factors:

- `await` at the beginning of a expression is usually quite noticeable, since it's the first thing you read and immediately frames the expression in a async context
- In practice, prefix await rarely is used in nested expressions (\* in my experience\*). If I had to speculate, I'd say this is because
  - nested awaits get awkward very quickly due to the parentheses required
  - they can obfuscate what's going on and so are naturally avoided.

As mentioned, this is partly improved by `.await?` likely being a very common pattern. I'd venture that `.await?` could likely be quite a bit more common than `.await`. And, to me, `.await?` is much more attention-drawing due to the extra sigil, and probably because you always watch out for `?` anyway when reading Rust.

**In conclusion** , I appreciate how difficult this decision is, and I'm very happy to not be on the lang team. 😉

---

_[View the full topic](https://internals.rust-lang.org/t/a-final-proposal-for-await-syntax/10021)._
