rust-lang / rust

Empowering everyone to build reliable and efficient software.
https://www.rust-lang.org
Other
96.69k stars 12.49k forks source link

Decide on bounds syntax for async closures (RFC 3668) #128129

Open traviscross opened 1 month ago

traviscross commented 1 month ago

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:

Other candidates discussed have included:

Tracking:

@rustbot labels +T-lang +I-lang-nominated

cc @compiler-errors @rust-lang/lang

kennytm commented 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.

compiler-errors commented 1 month ago

I think at this point it's basically useless to consider anything other than async Fn or AsyncFn.

nikomatsakis commented 1 month ago

@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.

dev-ardi commented 1 month ago

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.

mominshaikhdevs commented 1 month ago

+1 for async

casey commented 4 weeks ago

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.

mehcode commented 4 weeks ago

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.

compiler-errors commented 4 weeks ago

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.