I think the larger problem is naming the return type of async functions. With a regular function that returns an existential, we could do something like:
pub type FooIter = impl Iterator<Item = Foo>;
pub fn foo_iter() -> FooIter { ... }
With an async fn, I have no way of doing this. If I want to store tokio::TcpStream::connect futures, in a struct, I have to store a Pin<Box<dyn Future...>>, which feels unnecessary because I'm storing a single type. It is sometimes possible to make the type generic and push the creation of the futures to a standalone function.. but it's very unwieldy and doesn't work for all cases.
With min_type_alias_impl_trait, I am able to write something like:
#![feature(min_type_alias_impl_trait)]
use tokio::net::TcpStream;
type TcpStreamConnectFut = impl Future<Output = io::Result<TcpStream>>;
fn __tcp_stream_connect_defining_use() -> TcpStreamConnectFut {
TcpStream::connect("127.0.0.1:8080")
}
struct Foo {
connection_futs: Vec<TcpStreamConnectFut>,
}
But it would be nice if I could write typeof(TcpStream::connect)::Output, or similar. With this syntax, we could also write:
trait Foo where typeof(connect)::Output: Send + Sync {
async fn connect() -> io::Result<TcpStream>;
}
@nikomatsakis Also drew up a proposal for "inline futures" that would require this as well:
trait AsyncRead {
fn read(&mut self, buf: &mut [u8]) -> Future::PollFn<
typeof(<Self as AsyncRead>::poll_read)
>;
//
fn poll_read(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<usize, Error>>;
}
These problems were discussed in the past, but async/await was seemingly stabilized with some design holes. I think typeof is applicable to most of these: