-
Notifications
You must be signed in to change notification settings - Fork 1.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Async closures #3668
Async closures #3668
Conversation
@rfcbot fcp merge This important work has been a long time coming. The RFC is well motivated, well written, and well specified. This solves a real problem, and by solving it, we'll be supporting libraries to innovate in new and interesting ways across the async Rust ecosystem. By carefully limiting what is exposed as part of the stable interface, the RFC leaves us future room to maneuver. Thanks to @compiler-errors for putting together this RFC and the currently-experimental implementation. |
Team member @traviscross has proposed to merge this. The next step is review by the rest of the tagged team members: Concerns:
Once a majority of reviewers approve (and at most 2 approvals are outstanding), this will enter its final comment period. If you spot a major issue that hasn't been raised at any point in this process, please speak up! cc @rust-lang/lang-advisors: FCP proposed for lang, please feel free to register concerns. |
I think you should use |
@programmerjake: That's a great point to raise. @rfcbot concern should-it-be-into-future |
Yeah, sure, that's definitely possible from a technical perspective. For example, I've implemented the change here: rust-lang/rust#127225. I'll wait a bit to see what T-lang thinks, though, before changing the RFC. There's a bit of friction introduced by making these traits harder to use with the ecosystem when calling functions that take async fn foo(closure: impl async Fn()) {
spawn(closure().into_future()).await;
// ^^^^^^^^^^^
} And similarly, all of the The only other question is whether the concrete future returned by calling a concrete async closure should also only implement just |
In my experience lately, it's generally more flexible to use the I think @compiler-errors raises some good points about the migration. Lots of code is already written to take a I also agree that having asymmetry between So given the state of things, it's probably better to treat the return Is there a way we could signal to the ecosystem that we'd like them to migrate towards taking |
I think this RFC is great as-is. Thanks for writing this RFC and the implementation, @compiler-errors! @rfcbot reviewed
Interesting question. I replied in the thread but so far I do not see a compelling reason to do this. I think the compatibility headaches mentioned above and the general inconvenience of another layer of indirection are good reasons to avoid it. |
Iinterfaces based on |
|
I don't really think mention
This RFC specifically chooses not to generalize the |
I don’t think this
|
If we did introduce an We're reserving quite a lot of space for
I'm not super convinced that users (except for the curious ones) really care about looking at the If we find out that users are confusingly going to the
The paren sugar does not exist just to signal different lifetime elision behavior. It's pretty clear to me that it exists to give people an intuitive way to write Fn-like bounds with Fn-like syntax. Like, it's the only syntax that allows The lifetime elision behavior is a useful side effect that mirrors how fn pointers and closures' lifetime resolution work, but that's obviously not like the only reason to have them.
And I could make an equally useful argument that
I think it's uncharitable to suggest that we're only doing this because we think that users are stupid -- that feels kinda inflammatory. Of course users can read and parse
It is not backwards-compatible to stabilize If we stabilize |
Regarding Concrete async closures themselves, e.g. This is what @compiler-errors put up in the PR rust-lang/rust#127225 for discussion. The rationale for this would be that, in the case of concrete async closures, we know that they do implement both And unlike with the concrete async closures, where there's a comparable for us to want to be consistent with ( |
The feature gate for async closures is unfortunately in the singular, `async_closure`, and while that's not a stable commitment, it's probably too much of a pain to change that. But that doesn't mean that we can't name the file in the plural, so let's do that.
As it turns out, `AsyncFn()` probably commits our direction on generalized `async` trait bound modifiers to the same degree as `async Fn()`. Let's describe this. CE brought up this excellent point.
text/3668-async-closures.md
Outdated
|
||
Some have argued that using `F: AsyncFn() -> T` rather than `F: async Fn() -> T` would better save space for whatever we might want the semantics to be if we were to later adopt generalized `async` trait bound modifiers. | ||
|
||
We don't think this is correct in a practical sense. If we were give meaning to and stabilize `AsyncFn()` trait bounds, and then later, due to work on generalized `async` trait bound modifiers, we were to give a different meaning to `async Fn()`, that would seem so undesirable that it's hard to imagine we would ever actually do it. People would too strongly expect `AsyncFn()` and `async Fn()` to work in the same way. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What about a future where async Fn()
still has no meaning, but async SomeOtherTrait
does, in a way that is not analogous to AsyncFn()
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Then those meanings can coexist since by definition they don't overlap.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I also feel like at this point it's not productive to debate against a "what if" that's quantified over a space of possibilities that's not really enumerable. I'm happy to say that any async Trait
design that conflicts with at least the broad, user-facing observables of the definition of async Fn
is not worth considering.
5973093
to
d4aa94c
Compare
d4aa94c
to
86ad484
Compare
add the note in one other place Co-authored-by: Josh Triplett <[email protected]>
The concern about the proposed @rfcbot resolved use-AsyncFn-rather-than-async-Fn |
🔔 This is now entering its final comment period, as per the review above. 🔔 |
For reference, to make sure details discussed in a lang design meeting get reflected here: we also discussed several alternative syntactic sugars (including |
…li-obk Gate `AsyncFn*` under `async_closure` feature T-lang has not come to a consensus on the naming of async closure callable bounds, and as part of allowing the async closures RFC merge, we agreed to place `AsyncFn` under the same gate as `async Fn` so that these syntaxes can be evaluated in parallel. See rust-lang/rfcs#3668 (comment) r? oli-obk
Rollup merge of rust-lang#128120 - compiler-errors:async-fn-name, r=oli-obk Gate `AsyncFn*` under `async_closure` feature T-lang has not come to a consensus on the naming of async closure callable bounds, and as part of allowing the async closures RFC merge, we agreed to place `AsyncFn` under the same gate as `async Fn` so that these syntaxes can be evaluated in parallel. See rust-lang/rfcs#3668 (comment) r? oli-obk
Gate `AsyncFn*` under `async_closure` feature T-lang has not come to a consensus on the naming of async closure callable bounds, and as part of allowing the async closures RFC merge, we agreed to place `AsyncFn` under the same gate as `async Fn` so that these syntaxes can be evaluated in parallel. See rust-lang/rfcs#3668 (comment) r? oli-obk
There have been some questions raised both in this thread and other places about the forward-compatibility of this design with a possible Effect Generics design. The Effects Initiative has discussed this and as far as we can tell, this RFC does not pose any forward-compatibility concerns. From the Future Possibilities section of this RFC:
We agree with this assessment. This RFC only expands the use of the |
The final comment period, with a disposition to merge, as per the review above, is now complete. As the automated representative of the governance process, I would like to thank the author for their work and everyone else who contributed. This will be merged soon. |
The lang team has accepted this RFC, and we've now merged it. Thanks to @compiler-errors for pushing forward this important work, and thanks to all those who reviewed the RFC and provided useful feedback. For further updates, please follow the tracking issue: |
This RFC adds an
async
bound modifier to theFn
family of trait bounds. The combination desugars to a set of perma-unstableAsyncFn{,Mut,Once}
traits that parallel the currentFn{,Mut,Once}
traits.These traits give users the ability to express bounds for async callable types that are higher-ranked, and allow async closures to return futures which borrow from the closure's captures.
This RFC also connects these traits to the
async || {}
closure syntax, as originally laid out in RFC 2394, and confirms the necessity of a first-class async closure syntax.Rendered
For additional background, see this blog post (which is referenced in the RFC):
Tracking:
#![feature(async_closure)]
(RFC 2394 / RFC 3668) rust#62290