# Pre-RFC: Await generators directly

**URL:** <https://internals.rust-lang.org/t/pre-rfc-await-generators-directly/7202>\
**Category:** language design\
**Created:** [March 31, 2018, 11:33pm UTC](https://internals.rust-lang.org/t/pre-rfc-await-generators-directly/7202 "2018-03-31T23:33:15Z")\
**Posts on this page:** 12\
**Page:** 1

<div class="post-metadata">

**Author:** ![rpjohnst](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/rpjohnst/32/9524_2.png) [@rpjohnst](https://internals.rust-lang.org/u/rpjohnst)\
**Post date:** [March 31, 2018, 11:33pm UTC](https://internals.rust-lang.org/t/pre-rfc-await-generators-directly/7202/1 "2018-03-31T23:33:15Z")

</div>

# Summary

Make the await operation available directly to generators, independent of the way they are used- whether as `Future`s, `Iterator`s, or application-specific types. Provide generator items instead of generator expressions. Limit the use of traits like `Future` to places they are actually used in the program source.

(The networking WG is currently putting together an RFC for async/await syntax. This is intended as early input to that process.)

# Motivation

The current implementation of generators provides closure-like generator expressions as the sole method of constructing a generator value. The `futures-await` crate wraps this in `#[async]` functions which return `impl Future`, and provides the `await!` macro as the sole method of awaiting a generator value.

However, the await operation is also useful in many other contexts: iterators, GUI event handlers, game logic, interrupt handlers, etc. Many of these don’t need the `Future` trait or the `Context`/`Waker` system it implies.

We can make generators more useful in non-futures-based contexts by providing these features directly to generators- generator items instead of functions returning `impl Future`, and an await operation that applies directly to those generator items.

# Guide-level explanation

A _generator_ or _async function_ is a function that can be suspended and resumed part-way through its execution. For example:

```rust
async fn counter(limit: u32) yield u32 -> u32 {
    let mut i = 0;
    while i < limit {
        yield i;
        i += 1;
    }
    limit
}

```

A generator cannot be called from a non-generator function. It _can_ be called from another generator, or be used to construct a `Generator` value. Calling a generator causes everything it yields to appear as if it were yielded from the caller:

```rust
async fn two_counters() yield u32 {
    let x = counter(1);
    println!("{}", x);
    let y = counter(2);
    println!("{}", y);
}

```

```rust
let c = two_counters::new();
assert_eq!(c.resume(), GeneratorState::Yielded(0));
assert_eq!(c.resume(), GeneratorState::Yielded(0)); // also prints 1
assert_eq!(c.resume(), GeneratorState::Yielded(1));
assert_eq!(c.resume(), GeneratorState::Complete(())); // also prints 2

```

Traits like `Future`, `Stream`, and `Iterator` are implemented for wrapper types, to provide APIs specific to those contexts:

```rust
// generator yielding Async<T> implement IntoFuture:
tokio::run(async {
    let page = get_page_text("https://example.com/");
    // ...
});

```

```rust
// generators yielding T and returning () implement IntoIterator:
for i in two_counters() {
    println!("{}", i);
}

```

# Reference-level explanation

## Generator types and values

A generator item is syntactically a function prefixed with the `async` keyword. It can also specify a type to yield, which like the return type defaults to `()` if unspecified:

```rust
async fn generator(t: T, u: U) yield V -> W { ... }

```

A generator expression is syntactically a closure with no arguments, prefixed with the `async` keyword. It can also specify a type to yield the same way, and evaluates to a value with an anonymous type:

```rust
async yield V -> W { ... }

```

A generator item declares a type. That type, and the anonymous types of generator expressions, implement the `Generator` trait, which now also provides a single static method for construction. For example, the `counter` generator above is equivalent to this:

```rust
struct counter(...);

impl Generator for counter {
    type Args = (u32,);
    type Yield = u32;
    type Return = u32;

    extern "rust-call" fn new(args: Args) -> Self { ... }
    fn resume(&mut self) -> GeneratorState<Yield, Return> { ... }
}

```

A generator body has two additional capabilities beyond a normal function body:

- It can `yield` a value to its resumer, as in today’s implementation.
- It can directly invoke another generator as if it were a function, which _awaits_ it. This constructs a generator value of that type and resumes it repeatedly, yielding what it yields, until it completes, when it evaluates to its return value.

## Generator methods

Inherent impls and trait impls can contain generator items. They behave much like associated types, though awaiting them looks like a method call:

```rust
trait Trait {
    async fn g(&self) yield i32;
}

async fn async_caller<T: Trait>(t: T) yield i32 {
    t.g();
}

fn caller<T: Trait>(t: T) {
    let g = T::g::new(t);
    let _: GeneratorState<i32, ()> = g.resume();
}

```

This does mean that generic generator trait methods are blocked on generic associated types.

# Drawbacks

- Somewhat more work to implement than converting `futures-await`'s macros to language features.
- More design work to be done around `async for`- see below.
- Probably more.

# Rationale and Alternatives

## Generator composition

The main alternative design today is represented by the `futures-await` crate. There, only futures can be awaited, and any other use of generators must resume its callees in a loop manually.

This design lifts that restriction, and also makes it easy to bring futures back into a generator context- `Future` might have a method `async fn await(&mut self) yield Pending -> Output` that contains such a polling loop.

## Debugging and optimization

This design can improve the debugging experience. Awaiting a generator no longer goes through a wrapper type’s `poll` function, allowing debuggers to step directly into the callee. Further, stepping into a `resume()` can know to break only in the inner-most generator.

This design is also partially forwards-compatible with optimizations like a [CPS transform for generators](https://internals.rust-lang.org/t/pre-rfc-cps-transform-for-generators/7120). (The dependence does not go the other way- we do not need anything from the CPS transform design to get the benefits of this design.)

## API design

This design also neatly sidesteps two sources of potential confusion:

With `futures-await`, you can call an async function from a synchronous function, and get back a future. You might reasonably look at `Future`'s methods to try to extract the value, or even get an “unused value” warning. But with this design, you must either invoke the async function from an async context, or intentionally construct a generator value from it.

With any futures-based await syntax, there is a question of whether async functions should include `impl Future` somewhere in their return type or declaration. C# async functions and C++ coroutines _do_ include this information; Kotlin coroutines do not; Python and Javascript don’t specify types at all. This design decouples generators from futures so this question does not arise at all.

It may not even be necessary to put `Future` in the standard library to get async syntax (though it may still be desirable for other reasons).

# Unresolved questions

## `yield`

As described above, a generator is suspended by yielding a value. Another option, potentially more flexible, might be something that looks like call-with-current-continuation:

```rust
suspend me {
    /* me is a reference to the outer-most generator */
    /* this block's value is yielded */
}

```

Another question around `yield` is whether it should return a value on resume, and if so how. The first resumption of a generator does not have matching a `yield` expression. This might be solved by running the first segment of a generator into its `new` method, but this complicates self-referential generators and reduces the benefit of this design’s clear separation between construction and resumption.

## `async for`

Two traits from the `futures` crate neatly represent the async world’s versions of values and iterators- `Future` is to `T` as `Stream` is to `Iterator<Item = T>` (assuming `Future`'s `Item`/`Error` are combined into a single `Output`). However, generators introduce another trait. `Generator` is somewhere in between and below these two traits, depending on how you look at it.

I see a couple of ways to integrate generators with `Future`: a blanket impl for generators that yield `()`, or to better express intent, a blanket impl for generators that yield some marker type- perhaps a ZST `struct Pending;`.

This design could be expanded to `Stream` as a blanket impl for generators that yield `Option<T>`, or again an equivalent marker type. But this starts to feel kind of messy- how do you await a normal `Future`-style generator here, since those yield `()`? Some kind of `?`-operator-like conversion? How does that interact with the potential for a CPS transform?

And worse, how do you do iterator combinators here? What’s the equivalent for `IntoIterator` when you write `async for`? It feels like what we really want is a new trait, equivalent to `Iterator` but with an `async` `next` method:

```rust
trait AsyncIterator {
    type Item;
    async fn next(&mut self) yield ??? -> Item;
}

```

But then we’re back to hand-writing the iterator-level state machine. Is the answer yet another operation, like `futures-await` has with `#[async_stream]` and `stream_yield!`?

Perhaps, by analogy to a hypothetical `const impl`, we could even reuse the same `trait Iterator` in both contexts.

## Syntax

I kind of like the lack of an extra `await` keyword, but really all the syntax here is up for bikeshedding as far as I’m concerned. It’s not really the point of this pre-RFC.

---

<div class="post-metadata">

**Author:** ![jmst](https://avatars.discourse-cdn.com/v4/letter/j/41988e/32.png) [@jmst](https://internals.rust-lang.org/u/jmst)\
**Post date:** [April 1, 2018, 12:24am UTC](https://internals.rust-lang.org/t/pre-rfc-await-generators-directly/7202/2 "2018-04-01T00:24:24Z")

</div>

Why make this “await” functionality built-in when it can just be written explicitly as a loop that calls the “awaited” generator and yields?

Non-future based contexts can already use the generator functionality directly, and maybe a propagate\_yield!() macro could be added if this yield propagation pattern turns out to be frequently used.

More fundamentally the fact that something that looks like a function call actually automatically yields seems totally unacceptable (Rust seeks to make all such control flow explicit, see for instance the “?” operator), and also it would only work if the yield types match (with no way to provide a transformation function, for instance).

I general, not clear why this would be better rather than worse compared to the current generator syntax with async/await built on top as a library/plugin.

---

<div class="post-metadata">

**Author:** ![comex](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/comex/32/2587_2.png) [@comex](https://internals.rust-lang.org/u/comex)\
**Post date:** [April 1, 2018, 12:33am UTC](https://internals.rust-lang.org/t/pre-rfc-await-generators-directly/7202/3 "2018-04-01T00:33:01Z")

</div>

The usual argument for making `await` explicit, in any language, is that it makes it clear which calls can suspend the current coroutine (potentially blocking, and potentially allowing other coroutines to alter state) and which can’t. As @jmst mentioned, that seems to fit pretty well with Rust’s existing decision to make unwinding points explicit.

However, I can see the argument for making `await` a builtin feature that can be used in more scenarios. Dedicated syntax could also be more succinct: `await foo()` vs. `await!(foo())`.

---

<div class="post-metadata">

**Author:** ![rpjohnst](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/rpjohnst/32/9524_2.png) [@rpjohnst](https://internals.rust-lang.org/u/rpjohnst)\
**Post date:** [April 1, 2018, 1:08am UTC](https://internals.rust-lang.org/t/pre-rfc-await-generators-directly/7202/4 "2018-04-01T01:08:23Z")

</div>

> [@jmst](#):
>
> Why make this “await” functionality built-in when it can just be written explicitly as a loop that calls the “awaited” generator and yields?

That's covered in the rationale section- making it built-in makes it easier to compose generators, and makes it easier to write good tools for, and makes it easier to switch around the calling convention in the future. There's a single, canonical "await" operation that can be e.g. put into debug info or compiled down to something other than a loop.

For that matter, I believe it was already intended for await to become built-in, regardless of what I wrote here. All I'm proposing is to make it built-in _for generators_ rather than for futures.

> [@jmst](#):
>
> More fundamentally the fact that something that looks like a function call actually automatically yields seems totally unacceptable (Rust seeks to make all such control flow explicit, see for instance the “?” operator)

As far as syntax goes, making it explicit like `await foo()` doesn't alter the main point I'm making here. I certainly understand the analogy to `?` and the benefits of explicit suspension points.

Three reasons to make it implicit:

- The explicit `await some_future.await()` is redundant.
- The function is already marked `async`. `unsafe` functions and blocks don't mark every unsafe operation they contain, it's enough to mark the whole thing once.
- An awaited future is always (often?) a `Result`, which means it's often used with `?`. The precedence of `await foo()?` is confusing; `(await foo())?` is ugly; `await(foo())?` is hardly better than `await!(foo())?`.

Perhaps if it is explicit it should be another suffix operator, to preserve the order of the chain of operations? It does look rather strange that way (`foo() await ?`, or `foo()@?` if you can stomach the sigil (I can't)).

> [@jmst](#):
>
> it would only work if the yield types match (with no way to provide a transformation function, for instance).

Yes, it only works if the yield types match. But this is a fundamental aspect of await, regardless of how it's implemented.

There _is_ a way to provide a transformation function- build the generator explicitly and await an async map method on it. This is the exact same solution as with futures, just without tying yourself to that particular trait.

---

<div class="post-metadata">

**Author:** ![Nemo157](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/nemo157/32/11585_2.png) [@Nemo157](https://internals.rust-lang.org/u/Nemo157)\
**Post date:** [April 1, 2018, 8:50am UTC](https://internals.rust-lang.org/t/pre-rfc-await-generators-directly/7202/5 "2018-04-01T08:50:34Z")

</div>

`async`/`await` nomenclature seems very tied to the `futures` use-case of generators. The auto-yielding of sub-generators also seems only useful for generators implementing `Future` specifically (I believe neither the `Iterator` nor the `Stream` use cases would want this), for example this seems odd to me:

```rust
async fn range(start: u32, end: u32) yield u32 -> () {
    for val in start..end {
        yield val;
     }
}

async fn range_twice(start: u32, end: u32) yield u32 -> () {
    range(start, end);
    range(start, end);
}

```

What I have been using for this so far is a `yield_from!` macro (inspired by Python’s `yield from` syntax). I wonder if there’s a way to have a general `yield from` or similar syntax for generators that can be built on to offer a more specific `await` for `futures`.

There’s also the difficulty with `futures` 0.2 that somehow the context argument needs to be passed down. I’m still hopeful that we will get “generator arguments” back at some point to allow this, have you considered how this might be compatible with a trait similar to

```rust
trait Generator {
    type Args;
    type Yield;
    type Return;

    fn resume(&mut self, args: Args) -> GeneratorState<Yield, Return>
}

```

---

<div class="post-metadata">

**Author:** ![rpjohnst](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/rpjohnst/32/9524_2.png) [@rpjohnst](https://internals.rust-lang.org/u/rpjohnst)\
**Post date:** [April 1, 2018, 7:16pm UTC](https://internals.rust-lang.org/t/pre-rfc-await-generators-directly/7202/6 "2018-04-01T19:16:51Z")

</div>

Notably, Python's `yield from` and `await` are almost exactly the same internally- `await` is a later addition that performs the identical operation after a type check. So however it looks syntactically it's certainly valuable for both futures and iterators, with the same arguments as above for leaving it implicit.

> [@Nemo157](#):
>
> There’s also the difficulty with futures 0.2 that somehow the context argument needs to be passed down. I’m still hopeful that we will get “generator arguments” back at some point to allow this

That could certainly work. We would need to figure out the disparity between the first resumption and later resumptions. Perhaps by running the first segment as part of construction and passing the context as an argument as well? Or by repurposing the argument list to describe the values passed into `resume`? Or by giving a name to the yielded value as part of the declaration:

```rust
async fn f() yield(cx: &mut task::Context) Pending -> Output {
    /* cx is a new binding each resumption */
}

```

Or perhaps even using the call/cc-like syntax, if we don't want to follow the model of `yield` returning a value:

```rust
async fn f() yield(&mut task::Context) Pending -> Output {
    suspend me, cx {
        /* me is the generator */
        /* cx is the value passed into resume */
    }
}

```

Of course there's always thread-locals, which is how `futures-await` currently works even under futures 0.2.

---

<div class="post-metadata">

**Author:** ![Nemo157](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/nemo157/32/11585_2.png) [@Nemo157](https://internals.rust-lang.org/u/Nemo157)\
**Post date:** [April 1, 2018, 9:20pm UTC](https://internals.rust-lang.org/t/pre-rfc-await-generators-directly/7202/7 "2018-04-01T21:20:08Z")

</div>

After reading the relevant PEPs ([PEP 255](https://www.python.org/dev/peps/pep-0255/) for the basic generators, [PEP 342](https://www.python.org/dev/peps/pep-0342/) for the addition of sending arguments in, [PEP 380](https://www.python.org/dev/peps/pep-0255/) for the addition of `yield from`) I think there's just one extension to your proposal that would be needed to nicely support resume arguments:

> To be able to `await`/`yield from`/implicitly wait for a sub-generator, it must have compatible yield and resume types.

Specifically given the trait definition at the end of this post it must be some `Generator<Yield = Self::Yield, Resume = Self::Resume>`.

This comes almost directly from how `yield from` works in PEP 380 (minus some minor back-compat concerns), all arguments passed in are delegated directly to the sub-generator and yielded values are yielded back. The `Yield` types matching also appear to be an un-mentioned requirement of your original post.

This results in a trait

```rust
trait Generator {
    type Args;
    type Resume;
    type Yield;
    type Return;

    extern "rust-call" fn new(args: Self::Args) -> Self;
    fn resume(&mut self, args: Self::Resume) -> GeneratorState<Self::Yield, Self::Return>;
}

```

You can see how this can be used to define `Iterator`, `Future` or `Stream` implementations in [this playground](https://play.rust-lang.org/?gist=ec7c3daf37f58bbdc36b921e4f1152f6&version=nightly).

As you mentioned, there is still a relatively major unresolved question with argument taking on how to get the first argument in to the generator. Python was forced to basically have the equivalent of `fn resume(&mut self, args: Option<Self::Resume>)` and say that the first call _must_ pass `None` and all remaning calls should pass the actual arguments. I hope it's possible to come up with a better plan for this without backwards compatibility concerns. (I should look back at the old implementation and discussion on the original generators RFC at some point...)

* * *

Anyway, the whole point of this post is that your current proposal is definitely forwards-compatible with supporting generator arguments in the future (well, as long as the trait remains unstable anyway).

It should also be forwards-compatible with CPS (although I must admit I haven't really followed the details of it in your post fully). Since all the resumed and yielded types are compatible at all levels in a single CPS transformed generator stack the only incompatibility between the function types is the `Self` type, same as without any arguments, so however that's being handled should be capable of handling the arguments easily.

 

> **thread-locals...**
>
> > Of course there’s always thread-locals, which is how `futures-await` currently works even under futures 0.2.
> 
> Yeah, great for those of you with runtime threading libraries 😢, I'm currently going through the pain of trying to work out a not-horrible method of making `futures-await` safe to use on `no_std` that will actually have a chance of being merged back upstream. Super easy to just ignore thread-safety when I can guarantee that I won't use threads/interrupts, but just promising isn't good enough for core libraries.

---

<div class="post-metadata">

**Author:** ![jmst](https://avatars.discourse-cdn.com/v4/letter/j/41988e/32.png) [@jmst](https://internals.rust-lang.org/u/jmst)\
**Post date:** [April 1, 2018, 11:07pm UTC](https://internals.rust-lang.org/t/pre-rfc-await-generators-directly/7202/8 "2018-04-01T23:07:07Z")

</div>

Why not just pass Resume as an argument to the generator?

That is, code would be like this

```rust
fn make_generator(a: A, b: B, ...) -> impl Generator<Resume = Res, Yield = ..., Return = ...> {
    move |r: Res| {
         ...
         let r: Res = yield ...;
         ...
         let r: Res = yield ...;
         ...
    }
}

```

Putting Args and new in the Generator trait itself seems wrong: a GeneratorFactory trait or a simple closure can be used if someone wants to abstract over them (just like Future and Iterator don’t have “new” methods).

It may seem to be possible to emulate Resume by yielding a closure that takes the Resume value, and then assigning that to a variable, but I think that to pass the borrow checker it would at least need an extra \<'a\> parameter on Yield (so the closure can die after resuming so we unborrow the variable), which requires ATC; this also requires the caller to store the closure, which requires it to be self-referencing, essentially requiring it to be another generator; so it seems we need Resume and can’t emulate it.

---

<div class="post-metadata">

**Author:** ![rpjohnst](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/rpjohnst/32/9524_2.png) [@rpjohnst](https://internals.rust-lang.org/u/rpjohnst)\
**Post date:** [April 2, 2018, 12:06am UTC](https://internals.rust-lang.org/t/pre-rfc-await-generators-directly/7202/9 "2018-04-02T00:06:25Z")

</div>

That’s one possibility, but then you’ve lost the ability to give generators a different set of initial arguments, outside of just using a function returning `impl Trait`, which makes the actual type unnameable. (Unless you _also_ add `typeof` or `abstract type`.)

Splitting `new` into a separate trait is fine- it just needs to be in _some_ trait so you can name the type you’re working with.

---

<div class="post-metadata">

**Author:** ![withoutboats](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/withoutboats/32/4560_2.png) [@withoutboats](https://internals.rust-lang.org/u/withoutboats)\
**Post date:** [April 2, 2018, 8:20am UTC](https://internals.rust-lang.org/t/pre-rfc-await-generators-directly/7202/10 "2018-04-02T08:20:38Z")

</div>

I’m working on an RFC for async/await syntax (as you may already know), and I definitely considered something in this space, where an async function and a generator are just the same thing (you may know this too, since I posted a gist on twitter a few months ago).

Ultimately I’ve moved away from that kind of unified design for a few reasons. First, I think users find it easier to model async and generators as separate functionalities when learning than to understand them as isomorphic. In contrast, I think the main benefit of unifying them is aesthetic, which isn’t supremely compelling.

The biggest reason not to do this, I think, is that I think having two separate functionalities makes it very easy to model streams, which currently are a bit of a problem syntactically (@Nemo157’s alternative pre-RFC has a proposal, but I’ll respond there why I’m unconvinced about that).

If we have both `async fn()` and generator (let’s call that `fn() yield`, we have a matrix:

| | Evaluated immediately | Evaluated asynchronously |
| --- | --- | --- |
| **Return once** | fn() -\> T | async fn() -\> T (Future) |
| **Yield many** | fn() yield T (Iterator) | async fn() yield T (Stream) |

---

<div class="post-metadata">

**Author:** ![rpjohnst](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/rpjohnst/32/9524_2.png) [@rpjohnst](https://internals.rust-lang.org/u/rpjohnst)\
**Post date:** [April 2, 2018, 5:15pm UTC](https://internals.rust-lang.org/t/pre-rfc-await-generators-directly/7202/11 "2018-04-02T17:15:37Z")

</div>

> [@withoutboats](#):
>
> having two separate functionalities makes it very easy to model streams, which currently are a bit of a problem syntactically

Completely agreed. I kind of danced around this in my unresolved questions but never really figured it out. That's a good way to put it.

I'm not really interested in mushing the two operations together, really- just making them available without depending on `Future`+`Context`+`Waker`. Perhaps that's not completely realistic, and maybe it's better to push directly on things like easier `no_std` futures and better debugging, but I'd like to keep trying a bit longer.

We could borrow from the concepts of effects or _scoped_ continuations (conceptually, not talking about CPS here): treat "suspending because we're not done yet" and "suspending because we've generated a value" as two independent+orthogonal operations; give them two different names and two different ways to interface with from the outside. (This sounds like where your RFC is going anyway?)

I also like the C# team's point (from @Nemo157's RFC thread) that the explicit inclusion of `Task` in the return type is for polymorphism of the await mechanism- I had noticed that as well. While we won't need to separate `StableFuture`+`Future`+`Box<Future>`, I do still think awaiting could be useful outside of the actual `Future` trait.

As a summary: I think what's left over from this proposal, given that we don't want "generators are async functions are streams," is this:

- The ability to swap out the await mechanism, not by changing a return type like C# or C++, but by using different wrappers/drivers.
  - In particular, eliminating extra `poll`-like stack frames between nested generators/async fns/etc.
  - This leaves the job of control flow to the compiler (making it easier to optimize and debug through) and the job of (interfacing with the) scheduler to the wrapper.

- Some kind of `yield from`-like capability that isn't just defined to desugar to a `loop { .. yield .. }`
  - In other words, a way to compose `fn() yield`s, and I suppose also a way to do both at once and compose `async fn() yield`s.
  - This, again, leaves the job of control flow to the compiler and the job of scheduler to the wrapper.

- The idea that these functions are only callable from the appropriate context, and that they must be instantiated some other way to cross the boundary.
  - I expect it would help users' mental models and learnability not to have the syntactic option of "calling" an `async fn` outside of an async block.

- Bikeshed-y syntax: when you're in a particular context, calling another function from that context shouldn't require any extra `await` syntax.
  - Given the idea of wrappers/drivers above, `await` syntax would lead to `await a_future.await()` (unless futures turn around and implement the native trait for the `async fn` context).
  - The function itself already specifies what context it's part of. `unsafe` doesn't mark every individual operation either, that level of granularity should be enough.
  - Any `await` syntax will frequently be used alongside `?`. `await foo()?` has wrong or unintuitive precedence; `(await foo())?` is ugly; `await(foo())?` has the same problems as `try!()` that drove us to `?`; `foo() await ?` is strange; `foo()@?` is too many sigils.

Finally, how feasible would it be to reuse the solutions for `Iterator` and `Future` by combining them, rather than just using a new trait `Stream`? Some kind of `async impl Iterator` maybe? Or maybe it's not worth it.

---

<div class="post-metadata">

**Author:** ![system](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/system/32/14092_2.png) [@system](https://internals.rust-lang.org/u/system)\
**Post date:** [March 25, 2019, 8:30am UTC](https://internals.rust-lang.org/t/pre-rfc-await-generators-directly/7202/12 "2019-03-25T08:30:00Z")

</div>

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.
