From 755ba05dd3718984a6e3a3083c7db8845876019f Mon Sep 17 00:00:00 2001 From: Josh Triplett Date: Mon, 6 May 2024 17:00:29 +0200 Subject: [PATCH 1/2] `async T` and `gen T` types Co-authored-by: Eric Holk --- text/0000-async-gen-types.md | 154 +++++++++++++++++++++++++++++++++++ 1 file changed, 154 insertions(+) create mode 100644 text/0000-async-gen-types.md diff --git a/text/0000-async-gen-types.md b/text/0000-async-gen-types.md new file mode 100644 index 00000000000..462e78e602a --- /dev/null +++ b/text/0000-async-gen-types.md @@ -0,0 +1,154 @@ +- Feature Name: `async_gen_types` +- Start Date: 2024-05-06 +- RFC PR: [rust-lang/rfcs#0000](https://github.com/rust-lang/rfcs/pull/0000) +- Rust Issue: [rust-lang/rust#0000](https://github.com/rust-lang/rust/issues/0000) + +# Summary +[summary]: #summary + +Allow the syntax `async T` and `gen T` as types, equivalent to +`impl Future` and `impl Iterator` respectively. Accept +them anywhere `impl Trait` can appear. + +# Motivation +[motivation]: #motivation + +Users working with asynchronous code may encounter `impl Future` +types. Users working with iterators may encounter `impl Iterator` +types. + +These types are long and cumbersome to work with. They may be the first time +a user will encounter an associated type, and they add verbosity that +obfuscates the `Output`/`Item` types that people care more about. In +particular, a function that combines multiple futures or iterators with other +types requires reading past a lot of syntactic overhead. + +Users do not encounter these types when consuming iterators with loops or +combinators (or in the future producing them with `gen` blocks), or when +producing or consuming futures using async/await syntax. + +The syntax proposed by this RFC provides the same benefits that the current +`async fn` syntax does (highlighting the future output type), but usable in any +type rather than only in function return values. + +# Explanation +[explanation]: #explanation + +In any context where you can write an `impl Trait` type, you can write +`async T`, which desugars to `impl Future`: + +```rust +fn future_seq(f1: async T, f2: async U) -> async (T, U) { + async { + (f1.await, f2.await) + } +} +``` + +Similarly, in any context where you can write an `impl Trait` type, you can +write `gen T`, which desugars to `impl Iterator`: + +```rust +fn iter_seq(g1: gen T, g2: gen T) -> gen T { + gen { + yield from g1; + yield from g2; + } +} +``` + +These syntaxes work exactly as their desugarings suggest, and can appear +anywhere their desugarings can appear. + +Compare these to the longhand versions of these two functions: + +```rust +fn future_seq( + f1: impl Future, + f2: impl Future, +) -> impl Future { + async { + (f1.await, f2.await) + } +} + +fn iter_seq( + g1: impl Iterator, + g2: impl Iterator) +-> impl Iterator { + gen { + yield from g1; + yield from g2; + } +} +``` + +Notice how much longer these are, and how much more syntax the user needs to +wade through to observe the types they care about. + +# Drawbacks +[drawbacks]: #drawbacks + +This adds an additional case to Rust type syntax. + +# Rationale and alternatives +[rationale-and-alternatives]: #rationale-and-alternatives + +We could introduce a mechanism to abbreviate `impl Future` as +`impl Future` or `impl Fut` or similar. However, this still leaves much +of the syntactic "weight" in place. In addition, this may confuse users by +obfuscating the difference between associated types and generic parameters. + +# Prior art +[prior-art]: #prior-art + +We have special syntaxes for arrays in types, `[T]` and `[T; N]`, which are +evocative of the corresponding value syntax for arrays. Similarly, the syntax +for tuple types `(A, B)` is evocative of the syntax for tuple values `(a, b)`. + +The use of `async fn` to hide the asynchronous type serves as a partial +precedent for this: the case made at the time was that users cared about the +output type of the future more than they cared about the `Future` trait. This +RFC extends that benefit to any place a type can appear. + +Similarly, `async` blocks do not require specifying the Future trait, and +neither do the proposed `gen` blocks. + +# Unresolved questions +[unresolved-questions]: #unresolved-questions + +The `gen T` syntax can be added as unstable right away, but should not be +stabilized until we stabilize the rest of `gen` support. + +Introducing `async T` as a type meaning `impl Future` would close +off the use of `async T` as a syntax for "asynchronous versions" of existing +types (e.g. `async File`). + +# Future possibilities +[future-possibilities]: #future-possibilities + +Once we add `async gen` support, we can add the corresponding type +`async gen T`, mapping to whatever type we use for async iterators. + +These syntaxes would work very well together with a syntax to abbreviate +functions consisting of a single block. + +For example: + +```rust +fn countup(limit: usize) -> gen usize +gen { + for x in 0..limit { + yield i; + } +} + +fn do_something_asynchronously() -> async () +async { + do_something().await; +} +``` + +Together, these mechanisms would provide a general solution for what might +otherwise motivate a `gen fn` feature. Using `gen T` as a type makes the return +type simple enough to not need to hide the type. From c0f010373dae619befbc735e6e03701f030cec64 Mon Sep 17 00:00:00 2001 From: Josh Triplett Date: Tue, 7 May 2024 10:45:38 +0200 Subject: [PATCH 2/2] RFC 3628 --- text/{0000-async-gen-types.md => 3628-async-gen-types.md} | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename text/{0000-async-gen-types.md => 3628-async-gen-types.md} (98%) diff --git a/text/0000-async-gen-types.md b/text/3628-async-gen-types.md similarity index 98% rename from text/0000-async-gen-types.md rename to text/3628-async-gen-types.md index 462e78e602a..f2c36cccc78 100644 --- a/text/0000-async-gen-types.md +++ b/text/3628-async-gen-types.md @@ -1,6 +1,6 @@ - Feature Name: `async_gen_types` - Start Date: 2024-05-06 -- RFC PR: [rust-lang/rfcs#0000](https://github.com/rust-lang/rfcs/pull/0000) +- RFC PR: [rust-lang/rfcs#3628](https://github.com/rust-lang/rfcs/pull/3628) - Rust Issue: [rust-lang/rust#0000](https://github.com/rust-lang/rust/issues/0000) # Summary