Sorry that you feel I glossed over this, I definitely do feel the pain of this point, I really donât like that I had to write a function signature like
pub fn read_exact<'a, 'b: 'a, R: Read + 'a>(
mut this: Pin<'a, R>,
buf: &'b mut [u8],
) -> impl StableFuture<Item = (), Error = Error<R::Error>>
+ Captures<'a>
+ Captures<'b>
But, I still feel that this is better solved as part of impl Trait than just avoided in async fn. Even if futures is the only use case where the current impl Trait lifetime capture rules are not the best; there are always going to be some functions that are easier to write using combinators instead of async fn, these are likely to have the exact same problem of capturing arguments in their closures and having to use an impl Future return type with way too many lifetime bounds.
In my current prototype (and, I believe, forced by the definition of Future and Stream) thereâs only one case (well, family of cases because of the error type) where the return value can implement both
for<E> impl Future<Item=(), Error=E> + Stream<Item=!, Error=E>
I would argue these two traits are isomorphic so thereâs no real problem being able to return a type that implements both.
This is a super-interesting idea, if you expand on it in your planned RFC I definitely canât wait to see it.
One case you didnât mention is ânominal existential typesâ, I have a set of traits I hope to eventually model using ATC and implement via nominal existential types, e.g. the nominal existential type + impl Trait in trait examples are actually split from one trait I want to be able to write:
pub trait CountDown {
type Counting<'a>: Future<Item = (), Error = !> + 'a;
fn start(&mut self, count: Duration) -> Self::Counting<'_>;
}
impl CountDown for Timer {
abstract type Counting<'a>: Future<Item = (), Error = !> + 'a;
#[async]
fn start(&mut self, count: Duration) -> Self::Counting<'_> {
...
}
}
Iâm still not certain that I need this over just using raw impl Trait in trait support, but this allows for adding additional constraints on the returned future:
fn foo<C>(countdown: C)
where
C: CountDown,
<C as CountDown>::Counting: Send + Unpin,
I guess the oft-mentioned typeof operator might provide an alternative that works with just impl Trait in trait
fn foo<C>(countdown: C)
where
C: CountDown,
typeof(<C as CountDown>::start)::Output: Send + Unpin,