-
Notifications
You must be signed in to change notification settings - Fork 14k
Description
As far as I understand the current design of AsyncFn* traits allows them to become somewhat of a “sugar” for a more generalized approach in the future. Quoting from the RFC:
Changing the underlying definition to use
LendingFn*As mentioned above,
async Fn*()trait bounds can be adjusted to desugar toLendingFn*+FnOncetrait bounds, using associated-type-bounds like:where F: async Fn() -> i32 // desugars to where F: for<'s> LendingFn<LendingOutput<'s>: Future<Output = i32>> + FnOnce<Output: Future<Output = i32>>This should be doable in a way that does not affect existing code, but remain blocked on improvements to higher-ranked trait bounds around GATs. Any changes along these lines remain implementation details unless we decide separately to stabilize more user-observable aspects of the
AsyncFn*trait, which is not likely to happen soon.
In particular, the case for AsyncFnOnce seems pretty clear. It’s a future possibility (which is IMO very desirable) that AsyncFnOnce(Args…) -> R might be automatically implemented for any implementor of FnOnce(Args…) -> F that returns some F: Future<Output = R>; either by turning it into a sort of “alias” (in a way that avoids the shortcomings mentioned in the RFC) or by finding a way to re-structure the blanket impls.
In particular, IMO it’s a very relevant future possibility that Box<dyn FnOnce(Args…) -> Pin<Box<dyn Future<Output = R> [+ Send] [+Sync]>> could become an implementor of AsyncFnOnce(Args…) -> R in the future.
But #[fundamental] kills this possibility, as the following code compiles successfully, powered by the negative reasoning that #[fundamental] provides:
use std::pin::Pin;
use std::future::Future;
type BoxedFnOnceReturningBoxFuture = Box<dyn FnOnce() -> Pin<Box<dyn Future<Output = ()>>>>;
trait MyTraitNoOverlap {}
impl MyTraitNoOverlap for BoxedFnOnceReturningBoxFuture {}
impl<F: AsyncFnOnce()> MyTraitNoOverlap for F {}I was unable to find any prior discussion about the value of why these traits (AsyncFn, AsyncFnMut, AsyncFnOnce) are marked #[fundamental] in the first place. I can imagine it’s perhaps by analogy to Fn, FnMut, FnOnce being marked as such. But this decision is an important trade-off that should be considered.
As far as I can tell, there should be no issue in simply removing the #[fundamental] markers from AsyncFn, AsyncFnMut, AsyncFnOnce before they’re stabilized in 1.85. Testing this locally, std still compiles find, and UI tests pass.
It should always be backwards-compatible to add back the #[fundamental] marker later.
@rustbot label T-compiler, T-libs-api, F-async_closure, C-discussion