Open traviscross opened 1 month ago
Why are the 3 alternatives even considered in the first place? It feels like the team is trying to setup strawmans to divert attention away from the pros and cons between async FnMut() -> T
vs AsyncFnMut() -> T
.
If F: async mut || -> T
is valid I would have expected F: mut || -> T
should also be introduced and this is so punctuation-heavy that hurts searchability and teachability. And F: async mut fn() -> T
is doubly worse because fn() -> T
is already a valid type not a trait. Even if these 3 are included as experiments I highly doubt if final consensus would land on them.
I think at this point it's basically useless to consider anything other than async Fn
or AsyncFn
.
@kennytm
...It feels like the team is trying to setup strawmans to divert attention away...
I agree with you that we should just limit our focus to async Fn
and AsyncFn
.
However, this summary implies to me bad faith, and I don't think that's warranted. Those suggestions arose because there were some who felt that having some kind of syntax makes sense (for a variety of reasons, but mostly about forwards compatibility) but specifically didn't like async Fn
. that said, one of the reasons I don't like those proposals is precisely that I'd expect them to also be used for synchronous functions, and I think that's a pretty invasive and unwarranted change.
As a user I expect that async
prefacing a function desugars to the same thing but returning a future so the symmetry feels correct and more intuitive.
+1 for async
I personally find AsyncFnMut() -> T
to be a little more intuitive than async FnMut() -> T
.
I think the reason is that the fn
keyword isn't used in function types, it's Fn
and friends. If a function type could be written as fn() -> T
, then I think async fn() -> T
would make a lot of sense, but since it's Fn() -> T
, I think the non keyword version, AsyncFn() -> T
is a bit more consistent.
I think we need to take this and look in the future at other potential async traits.
If we go with F: async Fn()
here I personally will want to see T: async Iterator<Item = i32>
.
Likewise, if we go with F: AsyncFn()
, I will want to see T: AsyncIterator<Item = i32>
.
I'm not sure what I like more, to be honest. I can see T: async TRAIT
to be a nice easy-to-understand syntax when it works, but from a beginner's point-of-view, I'd expect every trait to be able to be async
by slapping async
in front of the trait name.
This thread is not the right place to have discussions. Please refer to zulip: https://rust-lang.zulipchat.com/#narrow/stream/213817-t-lang/topic/Async.20closures.20bounds.20syntax where a lot of this has been discussed at length.
This issue exists to track the requirement to decide this before stabilization, but like most tracking issues is not particularly a great place for discusions.
Please also refer to the RFC and the lang team notes where this was last discussed.
Prior to stabilization, we need to decide which syntax to use for async closure bounds. This was left as an open question in RFC 3668.
The main known candidates are:
F: async FnMut() -> T
F: AsyncFnMut() -> T
Other candidates discussed have included:
F: async mut fn() -> T
F: async mut () -> T
F: async mut || -> T
F: async fn(&mut self) -> T
F: AsyncFn(&mut self) -> T
F: async |&mut self| -> T
Tracking:
@rustbot labels +T-lang +I-lang-nominated
cc @compiler-errors @rust-lang/lang