Skip to content

Commit 4ddd80d

Browse files
committed
Prepare RFC 3654 to be merged
We've been using "tracking issue" rather than "rust issue" recently, so let's adjust that. Let's also use sentence case for the title and remove some remaining bits left over from the RFC template. And let's replace some Unicode characters that don't have ubiquitous font support with ASCII equivalents.
1 parent d01b3f2 commit 4ddd80d

File tree

1 file changed

+11
-36
lines changed

1 file changed

+11
-36
lines changed

text/3654-return-type-notation.md

+11-36
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
1-
# Return Type Notation in Bounds and Where-clauses
1+
# Return type notation (RTN) in bounds and where-clauses
22

33
- Feature Name: `return_type_notation`
44
- Start Date: 2024-06-04
55
- RFC PR: [rust-lang/rfcs#3654](https://github.com/rust-lang/rfcs/pull/3654)
6-
- Rust Issue: [rust-lang/rust#109417](https://github.com/rust-lang/rust/issues/109417)
6+
- Tracking Issue: [rust-lang/rust#109417](https://github.com/rust-lang/rust/issues/109417)
77

88
# Summary
99
[summary]: #summary
@@ -30,8 +30,6 @@ Examples of RTN usage allowed by this RFC include:
3030
# Motivation
3131
[motivation]: #motivation
3232

33-
> Why are we doing this? What use cases does it support? What is the expected outcome?
34-
3533
Rust now supports async fns and `-> impl Trait` in traits (acronymized as AFIT and RPITIT, respectively), but we currently lack the ability for users to declare additional bounds on the values returned by such functions. This is often referred to as the [Send bound problem][sbp], because the most acute manifestation is the inability to require that an `async fn` returns a `Send` future, but it is actually more general than both async fns and the `Send` trait (as discussed below).
3634

3735
[sbp]: https://smallcultfollowing.com/babysteps/blog/2023/02/01/async-trait-send-bounds-part-1-intro/
@@ -177,8 +175,8 @@ where
177175
S: Service<
178176
(),
179177
Response: Send,
180-
call(..): Send, // 👈 "the method `call`
181-
// returns a `Send` future"
178+
// "The method `call` returns a `Send` future."
179+
call(..): Send,
182180
> + Send + 'static,
183181
{
184182
tokio::spawn(async move {
@@ -213,7 +211,7 @@ where
213211
{
214212
fn widgets(&self) -> impl Iterator<Item = Widget> {
215213
self.factory.widgets().rev()
216-
// 👆 requires that the iterator be double-ended
214+
// ^^^ requires that the iterator be double-ended
217215
}
218216
}
219217
```
@@ -269,7 +267,7 @@ The function `spawn_call` can then be written as follows:
269267
async fn spawn_call<S>(service: S) -> S::Response
270268
where
271269
S: SendService<(), Response: Send> + 'static,
272-
// 👆 use the alias
270+
// ^^^^^^^^^^^ use the alias
273271
{
274272
tokio::spawn(async move {
275273
service.call(()).await // <--- OK!
@@ -306,8 +304,6 @@ While `SendBackend` may be convenient most of the time, it is also stricter than
306304
# Guide-level explanation
307305
[guide-level explanation]: #guide-level-explanation
308306

309-
> Explain the proposal as if it was already included in the language and you were teaching it to another Rust programmer.
310-
311307
Async functions can be used in many ways. The most common configuration is to use a *work stealing* setup, in which spawned tasks may migrate between threads. In this case, all futures have to be `Send` to ensure that this migration is safe. But many applications prefer to use a *thread-per-core* setup, in which tasks, once spawned, never move to another thread (one important special case is where the entire application runs on a single thread to begin with, common in embedded environments but also in e.g. Google's Fuchsia operating system).
312308

313309
For the most part, async functions today do not declare whether they are `Send` explicitly. Instead, when a future `F` is spawned on a multithreaded executor, the compiler determines whether it implements `Send`. So long as `F` results from an `async fn` that only calls other `async fn`s, the compiler can analyze the full range of possible executions. But there are limitations, especially around calls to async trait methods like `f.method()`. If the type of `f` is either a generic type or a `dyn` trait, the compiler cannot determine which impl will be used and hence cannot analyze the function body to see if it is `Send`. This can result in compilation errors.
@@ -492,14 +488,6 @@ When using a trait `MyTrait` that defines a sendable alias `SendMyTrait`...
492488
# Reference-level explanation
493489
[reference-level explanation]: #reference-level-explanation
494490

495-
>This is the technical portion of the RFC. Explain the design in sufficient detail that:
496-
>
497-
>- Its interaction with other features is clear.
498-
>- It is reasonably clear how the feature would be implemented.
499-
>- Corner cases are dissected by example.
500-
>
501-
>The section should return to the examples given in the previous section, and explain more fully how the detailed proposal makes those examples work.
502-
503491
## Background and running examples
504492

505493
### The `Widgets` trait
@@ -543,8 +531,8 @@ Type = i32
543531
| Type "::" AssociatedTypeName
544532
| "<" Type as TraitName Generics? ">" "::" AssociatedTypeName
545533
| ...
546-
| Type "::" MethodName "(" ".." ")" // 👈 new
547-
| "<" Type as TraitName Generics? ">" "::" MethodName "(" ".." ")" // 👈 new
534+
| Type "::" MethodName "(" ".." ")" // <--- new
535+
| "<" Type as TraitName Generics? ">" "::" MethodName "(" ".." ")" // <--- new
548536
549537
Generics = "<" Generic,* ">"
550538
Generic = Type | Lifetime | ...
@@ -566,7 +554,7 @@ TraitRef = TraitName "<" Generic,* AssociatedBound ">"
566554
567555
AssociatedBound = Identifier "=" Generic
568556
| Identifier ":" TraitRef // (from RFC #2289)
569-
| Identifier "(" ".." ")" ":" TraitRef // 👈 new
557+
| Identifier "(" ".." ")" ":" TraitRef // <--- new
570558
```
571559

572560
Examples: given the `Widgets` trait defined earlier in this section...
@@ -626,8 +614,6 @@ Although conceptually RTN could be used for any trait method, we choose to limit
626614
# Drawbacks
627615
[drawbacks]: #drawbacks
628616

629-
>Why should we *not* do this?
630-
631617
## Confusion about future type vs awaited type
632618

633619
When writing an async function, the future is implicit:
@@ -663,11 +649,6 @@ It is a consequence of existing precedent:
663649
# Rationale and alternatives
664650
[rationale and alternatives]: #rationale-and-alternatives
665651

666-
>- Why is this design the best in the space of possible designs?
667-
>- What other designs have been considered and what is the rationale for not choosing them?
668-
>- What is the impact of not doing this?
669-
>- If this is a language proposal, could this be done in a library or macro instead? Does the proposed change make Rust code easier or harder to read, understand, and maintain?
670-
671652
## What is the impact of not doing this?
672653

673654
The Async Working Group has performed [five case studies][cs] around the use of async functions in trait, covering usage in the following scenarios:
@@ -763,7 +744,7 @@ and a function bounding it
763744
fn start_health_check<H>(health_check: H, server: Server)
764745
where
765746
H: HealthCheck + Send + 'static,
766-
H::check(..): Send, // 👈 How would we write this with `typeof`?
747+
H::check(..): Send, // <--- How would we write this with `typeof`?
767748
```
768749

769750
To write the above with `typeof`, you would do something like this
@@ -821,7 +802,7 @@ might have been desugared as follows:
821802

822803
```rust
823804
trait Factory {
824-
type widgets<'a>: Iterator<Item = Widget>; // 👈 implicitly introduced
805+
type widgets<'a>: Iterator<Item = Widget>; // <--- implicitly introduced
825806
fn widgets(&self) -> Self::widgets<'_>;
826807
}
827808
```
@@ -951,8 +932,6 @@ C++ has [`decltype`](https://en.cppreference.com/w/cpp/language/decltype) expres
951932
# Unresolved questions
952933
[unresolved questions]: #unresolved-questions
953934

954-
>- What parts of the design do you expect to resolve through the implementation of this feature before stabilization?
955-
956935
## Does stabilizing `T::foo(..)` notation as a standalone type create a confusing inconsistency with `-> ()` shorthand?
957936

958937
Unlike a regular associated type, this RFC does not allow a trait bound that specifies the return type of a method, only the ability to put bounds on that return type.
@@ -965,10 +944,6 @@ Prior to stabilizing the "associated type position" syntax, we should be sure we
965944
# Future possibilities
966945
[future possibilities]: #future-possibilities
967946

968-
>Think about what the natural extension and evolution of your proposal would
969-
be and how it would affect the language and project as a whole in a holistic
970-
way.
971-
972947
## Implementing trait aliases
973948

974949
Referring to the `Service` trait specifically,

0 commit comments

Comments
 (0)