# An Alternative Syntax for Async Functions

**URL:** https://internals.rust-lang.org/t/an-alternative-syntax-for-async-functions/15255
**Category:** Uncategorized
**Created:** [September 1, 2021, 5:51pm UTC](https://internals.rust-lang.org/t/an-alternative-syntax-for-async-functions/15255 "2021-09-01T17:51:55Z")
**Posts on this page:** 20
**Page:** 1

<div class="post-metadata">

### Author: ![ibraheemdev](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/ibraheemdev/32/13406_2.png) [@ibraheemdev](https://internals.rust-lang.org/u/ibraheemdev)
#### Post date: [September 1, 2021, 5:51pm UTC](https://internals.rust-lang.org/t/an-alternative-syntax-for-async-functions/15255/1 "2021-09-01T17:51:55Z")

</div>

After the related discussion in [Idea of how to bound types that async methods return](https://internals.rust-lang.org/t/idea-of-how-to-bound-types-that-async-methods-return/14647), I decided to flesh out my thoughts in writing. I'd appreciate any thoughts or feedback.

> **[An Alternative Syntax for Async Functions](https://ibraheem.ca/writings/an-alternative-async-fn-syntax/)**
>
> After thinking about the async fn in traits problem for a while, I've come to the conclusion that the syntax Rust chose for async fn is the wrong one. Specifically, the fact that the returned future type is hidden is quite limiting. Here's how we can...

---

<div class="post-metadata">

### Author: ![tema2](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/tema2/32/6498_2.png) [@tema2](https://internals.rust-lang.org/u/tema2)
#### Post date: [September 1, 2021, 6:06pm UTC](https://internals.rust-lang.org/t/an-alternative-syntax-for-async-functions/15255/2 "2021-09-01T18:06:14Z")

</div>

In fact, the only actual problem I see here is people wanting `async fn` to be exact syntax for asynchrony in traits... Also, the syntax feels long.

As of async **functions** - I don't think we want to change this: it's stable and it works.

---

<div class="post-metadata">

### Author: ![ibraheemdev](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/ibraheemdev/32/13406_2.png) [@ibraheemdev](https://internals.rust-lang.org/u/ibraheemdev)
#### Post date: [September 1, 2021, 6:09pm UTC](https://internals.rust-lang.org/t/an-alternative-syntax-for-async-functions/15255/3 "2021-09-01T18:09:54Z")

</div>

You think async functions in traits should be different than regular async functions syntax-wise?

---

<div class="post-metadata">

### Author: ![CAD97](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/cad97/32/3460_2.png) [@CAD97](https://internals.rust-lang.org/u/CAD97)
#### Post date: [September 1, 2021, 6:15pm UTC](https://internals.rust-lang.org/t/an-alternative-syntax-for-async-functions/15255/4 "2021-09-01T18:15:09Z")

</div>

I think most people will disagree on the "is it too late" point, but I'll just note my disagreement and continue.

My biggest remaining note: in this version of `async`, what is the value of `async fn foo() -> _ {}` over `fn foo() -> _ {async{}}`? If it's `'all_inputs` -- why not just provide `'all_inputs` for normal `fn`? If it's error messages, why not just enable those for a function returning a tail position `async`?

Note that there's also the idea for `async` blocks, `try` blocks to support a syntax

```rust
fn foo() -> RetTy = async {
}

```

which I think delivers all the benefits you're potentially claiming, except being "the simple way to write `async`".

---

<div class="post-metadata">

### Author: ![tema2](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/tema2/32/6498_2.png) [@tema2](https://internals.rust-lang.org/u/tema2)
#### Post date: [September 1, 2021, 6:18pm UTC](https://internals.rust-lang.org/t/an-alternative-syntax-for-async-functions/15255/5 "2021-09-01T18:18:14Z")

</div>

Not that they should, but they definitely can.

---

<div class="post-metadata">

### Author: ![ibraheemdev](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/ibraheemdev/32/13406_2.png) [@ibraheemdev](https://internals.rust-lang.org/u/ibraheemdev)
#### Post date: [September 1, 2021, 6:21pm UTC](https://internals.rust-lang.org/t/an-alternative-syntax-for-async-functions/15255/6 "2021-09-01T18:21:09Z")

</div>

> I think most people will disagree on the "is it too late" point, but I'll just note my disagreement and continue.

I doubt the change will happen as well, but I thought I'd put it out there after all the talk about implicit await being added over an edition.

> what is the value of `async fn foo() -> _ {}` over `fn foo() -> _ {async{}}`

The value is saving the extra indentation, reducing the change from the current version, and staying similar to other languages.

> why not just provide `'all_inputs` for normal `fn`

`'input` would probably apply to all functions, not just `async` ones.

> Note that there's also the idea for `async` blocks, `try` blocks to support a syntax

That is interesting, I have not heard of that idea before.

---

<div class="post-metadata">

### Author: ![CAD97](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/cad97/32/3460_2.png) [@CAD97](https://internals.rust-lang.org/u/CAD97)
#### Post date: [September 1, 2021, 6:45pm UTC](https://internals.rust-lang.org/t/an-alternative-syntax-for-async-functions/15255/7 "2021-09-01T18:45:24Z")

</div>

One other big thing of note:

By your own admission, for trait `async`ronous functions,

> Note that the method isn't marked as `async` , because it doesn't need to be. The `async` _modifier_ can be used when implementing the trait:

So... why can't that just be the case with the current `async` syntax as well?

```rust
trait Foo {
    type FooFut: impl Future<Output = usize> + Send;
    fn foo(&self) -> Self::FooFut;
}

impl Foo for Bar {
    async fn foo(&self) -> usize {
        baz().await;
        1
    }
}

```

There's no reason this couldn't apply to current `async` syntax as well, so it's not so much an argument for not "hiding" the existential `impl Future` as it is an argument for allowing to write `async fn` to implement trait functions which return an existential `impl Future`.

> but I thought I'd put it out there after all the talk about implicit await being added over and edition.

I don't think anyone actually proposed this? I brought up implicit `await` again once as a "what if" for comparison purposes, but only to support the potential of using an explicit `async` for a spitballed `async` overloading feature.

It's an art (unfortunately) to tell what's being brought up as serious "the language should consider changing to be like" versus "this was discussed previously and the lessons learned then should be remembered" versus "here's a deliberately too-far proposal to compare against." I think all mentions of implicit `await` post the `.await` decision fall in the latter two camps.

* * *

Oh also, this wouldn't be possible as an edition change under current edition guidelines. One of the guidelines, in addition to "should be automatically `cargo fix`able in the case without macros," we have roughly "warning free code in all previous editions (with the migration lint group on) should compile cleanly in the new edition" and "it should be reasonable to write code that compiles warning free in all editions (not using edition-exclusive behavior, and/or using `k#`/`r#`)".

With an edition change to your `async fn`, there's no `async fn` that compiles correctly on both editions, so the "reasonable" state that would be `cargo fix`ed to is in fact just `fn foo() -> _ {async{}}`.

`cargo fix` IIRC doesn't also update the edition as well; it just applies always-machine-applicable error/warning suggested fixes to your code, so whatever it fixes to _must_ work in the edition that is being checked / migrated from.

It's really appealing to say "editions let us change whatever to fix things," but actually making changes beyond keyword reservations, changing defaults, or "it's technically breaking, but we could still potentially rationalize it," is going to be a very hard sell if not impossible to push through.

---

<div class="post-metadata">

### Author: ![ibraheemdev](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/ibraheemdev/32/13406_2.png) [@ibraheemdev](https://internals.rust-lang.org/u/ibraheemdev)
#### Post date: [September 1, 2021, 6:55pm UTC](https://internals.rust-lang.org/t/an-alternative-syntax-for-async-functions/15255/8 "2021-09-01T18:55:36Z")

</div>

> I don't think anyone actually proposed this?

The async working-group has been discussing it: [wg-async-foundations is now wg-async](https://rust-lang.github.io/wg-async-foundations/vision/unresolved_questions/await_or_not.html).

---

<div class="post-metadata">

### Author: ![ibraheemdev](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/ibraheemdev/32/13406_2.png) [@ibraheemdev](https://internals.rust-lang.org/u/ibraheemdev)
#### Post date: [September 1, 2021, 6:59pm UTC](https://internals.rust-lang.org/t/an-alternative-syntax-for-async-functions/15255/9 "2021-09-01T18:59:54Z")

</div>

> [@CAD97](#):
>
> So... why can't that just be the case with the current `async` syntax as well?

Sure, that's a possibility. The post is just my view on how things would work best, I'm not against picking and choosing parts of it that work well without breaking changes. I do think that making that the primary syntax would be much more consistent all around. It would be weird for users to do it one way for standalone/inherent async fns, and have to do it another way for traits.

---

<div class="post-metadata">

### Author: ![steffahn](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/steffahn/32/13288_2.png) [@steffahn](https://internals.rust-lang.org/u/steffahn)
#### Post date: [September 1, 2021, 7:07pm UTC](https://internals.rust-lang.org/t/an-alternative-syntax-for-async-functions/15255/10 "2021-09-01T19:07:28Z")

</div>

Side-note on this code:

> [@CAD97](#):
>
> ```rust
> trait Foo {
> type FooFut: impl Future<Output = usize> + Send;
> fn foo(&self) -> Self::FooFut;
> }
> 
> impl Foo for Bar {
> async fn foo(&self) -> usize {
> baz().await;
> 1
> }
> }
> 
> ```

(ignoring the incorrect additional `impl`)  
I think you’d need something like

```rust
trait Foo {
    type FooFut<'a>: Future<Output = usize> + Send + 'a
    where
        Self: 'a;
    fn foo(&self) -> Self::FooFut<'_>;
}

impl Foo for Bar {
    async fn foo(&self) -> usize {
        baz().await;
        1
    }
}

```

to make this work properly, because the future returned by an `async fn` captures the argument.

---

<div class="post-metadata">

### Author: ![ibraheemdev](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/ibraheemdev/32/13406_2.png) [@ibraheemdev](https://internals.rust-lang.org/u/ibraheemdev)
#### Post date: [September 1, 2021, 7:23pm UTC](https://internals.rust-lang.org/t/an-alternative-syntax-for-async-functions/15255/11 "2021-09-01T19:23:36Z")

</div>

That's true, although I believe the `+ 'a` is inferred, and there's discussion about whether the `Self: 'a` should be.

---

<div class="post-metadata">

### Author: ![atagunov](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/atagunov/32/5877_2.png) [@atagunov](https://internals.rust-lang.org/u/atagunov)
#### Post date: [September 1, 2021, 7:48pm UTC](https://internals.rust-lang.org/t/an-alternative-syntax-for-async-functions/15255/12 "2021-09-01T19:48:18Z")

</div>

Suggested syntax is very clean and self-explanatory even to an untrained eye.

> [@CAD97](#):
>
> warning free code ... should compile cleanly in the new edition

Could some next-best variant become the primary syntax  
relegating `async fn ` to deprecated status?

```rust
fn foo() -> impl Future<Output = usize> => async { 
    1
}

```

---

<div class="post-metadata">

### Author: ![ibraheemdev](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/ibraheemdev/32/13406_2.png) [@ibraheemdev](https://internals.rust-lang.org/u/ibraheemdev)
#### Post date: [September 1, 2021, 8:43pm UTC](https://internals.rust-lang.org/t/an-alternative-syntax-for-async-functions/15255/13 "2021-09-01T20:43:14Z")

</div>

Alternatively, `async fn foo() -> usize` could be a warning instead of a hard error on older editions.

---

<div class="post-metadata">

### Author: ![H2CO3](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/h2co3/32/2849_2.png) [@H2CO3](https://internals.rust-lang.org/u/H2CO3)
#### Post date: [September 2, 2021, 7:41am UTC](https://internals.rust-lang.org/t/an-alternative-syntax-for-async-functions/15255/14 "2021-09-02T07:41:23Z")

</div>

> [@ibraheemdev](#):
>
> implicit await being added over an edition.

Woah, where/when did that happen? I missed it. (And I think it's an absolutely horrible idea – at least I'd like to voice my dissent wherever it was discussed.)

---

<div class="post-metadata">

### Author: ![CAD97](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/cad97/32/3460_2.png) [@CAD97](https://internals.rust-lang.org/u/CAD97)
#### Post date: [September 2, 2021, 2:08pm UTC](https://internals.rust-lang.org/t/an-alternative-syntax-for-async-functions/15255/15 "2021-09-02T14:08:40Z")

</div>

> [@H2CO3](#):
>
> Woah, where/when did that happen? I missed it.

> [@ibraheemdev](#):
>
> The async working-group has been discussing it: [To await or not to await? - wg-async-foundations](https://rust-lang.github.io/wg-async-foundations/vision/unresolved_questions/await_or_not.html).

Based on [a Carl Lerche post](https://carllerche.com/2021/06/17/six-ways-to-make-async-rust-easier/).

However, I want to emphasize that this is in the "Unresolved Questions and Controversies" section of the wg-async documentation, and while it may have been discussed further in Zulip (I didn't check), it hasn't been discussed further in the repository beyond documentation.

I believe this would be the most relevant Zulip thread: [rust-lang Zulip #wg-async-foundations: Dropping `.await` - what else could or would change](https://rust-lang.zulipchat.com/#narrow/stream/187312-wg-async-foundations/topic/Dropping.20.60.2Eawait.60-.20what.20else.20could.20or.20would.20change)

---

<div class="post-metadata">

### Author: ![ibraheemdev](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/ibraheemdev/32/13406_2.png) [@ibraheemdev](https://internals.rust-lang.org/u/ibraheemdev)
#### Post date: [September 2, 2021, 2:46pm UTC](https://internals.rust-lang.org/t/an-alternative-syntax-for-async-functions/15255/16 "2021-09-02T14:46:23Z")

</div>

Yes, it was discussed on zulip after Carl Lerche's post. There was no serious proposal or anything, but it was mentioned that this is something that could potentially, hypothetically change:

> Just wondering, is this something that could actually change? It would be a pretty huge breaking change, no?

> We could certainly change it over an edition It would be a big migration though 🙂

---

<div class="post-metadata">

### Author: ![mcy](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/mcy/32/6512_2.png) [@mcy](https://internals.rust-lang.org/u/mcy)
#### Post date: [September 2, 2021, 2:50pm UTC](https://internals.rust-lang.org/t/an-alternative-syntax-for-async-functions/15255/17 "2021-09-02T14:50:34Z")

</div>

If you only care about bounds, add `return` as a production in the type syntax so you can write e.g.

```rust
await fn foo() -> T
where
  return: Send,
  i32: LolIdk<return>,

```

(Compare `Self`.)

This should have the same expressive power without stepping on anyone's toes.

(I am, in general, a big fan of using `return` in type position for this sort of thing.)

---

<div class="post-metadata">

### Author: ![ibraheemdev](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/ibraheemdev/32/13406_2.png) [@ibraheemdev](https://internals.rust-lang.org/u/ibraheemdev)
#### Post date: [September 6, 2021, 5:55pm UTC](https://internals.rust-lang.org/t/an-alternative-syntax-for-async-functions/15255/18 "2021-09-06T17:55:26Z")

</div>

How would you conditionally bound the output of an async trait method?

```rust
trait Foo {
    type Fut: Future<Output = usize>;
    async fn foo() -> Self::Fut;
}

fn call_foo<F>(foo: F) where F: Foo<Fut: Send> { ... }

```

---

<div class="post-metadata">

### Author: ![Mokuz](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/mokuz/32/7225_2.png) [@Mokuz](https://internals.rust-lang.org/u/Mokuz)
#### Post date: [September 6, 2021, 6:03pm UTC](https://internals.rust-lang.org/t/an-alternative-syntax-for-async-functions/15255/19 "2021-09-06T18:03:19Z")

</div>

instead of `return` it should be `Return` (breaking change!) similar to how `self` and `Self` behave so you could have

```rust
fn foo(f: impl Fn() -> i32) -> Vec<Box<dyn Fn() -> i32>> {
    let mut vec = Return::default();

    vec.push(f); 

    vec
} 

```

not sure how useful in this instance, but more consistent.

---

<div class="post-metadata">

### Author: ![ibraheemdev](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/ibraheemdev/32/13406_2.png) [@ibraheemdev](https://internals.rust-lang.org/u/ibraheemdev)
#### Post date: [September 6, 2021, 11:20pm UTC](https://internals.rust-lang.org/t/an-alternative-syntax-for-async-functions/15255/20 "2021-09-06T23:20:37Z")

</div>

At first glance, this could look like `return: Send` refers to `i32`. The function signature says that the function _returns_ an `i32` after all. Most beginners to async would probably assume that.

[Next page](https://internals.rust-lang.org/t/an-alternative-syntax-for-async-functions/15255.md?page=2)
