impl Trait in return position is not supported in traits (not even with nightly features). However, I think it should be easy to implement, if the return type is not constrained by generics and lifetimes defined in the function:
trait Foo<'a> {
fn bar(&'a self) -> impl Debug + 'a;
}
// this is roughly equivalent to
trait Foo<'a> {
type Bar: Debug + 'a;
fn bar(&'a self) -> Self::Bar;
}
The above code with the associated type works, and with #![feature(type_alias_impl_trait)], it's even possible to use it for opaque types:
impl<'a> Foo<'a> for String {
type Bar = impl Debug + 'a;
fn bar(&'a self) -> Self::Bar {
// note that this type can't be named!
self.chars().filter(|c| c.is_ascii())
}
}
However, it would be even nicer if impl Trait in return position was allowed here. What do you think?
Conceptually, GATs are fairly simple. Implementation wise, though, we’re still working on how to support them in rustc – this may require porting rustc to use chalk, though that’s not entirely clear. In any case, this work is definitely underway, but it’s going to take more time.
RF 2071 included the type Foo = impl Trait; feature under a different syntax, though iirc not long ago everyone agreed that type Foo = impl Trait; is the best syntax for it after all. Meta tracking issue for `impl Trait` · Issue #63066 · rust-lang/rust · GitHub includes it explicitly on the checklist of impl Trait-related things we need to do.
EDIT: That same checklist also has Meta tracking issue for `impl Trait` · Issue #63066 · rust-lang/rust · GitHub for the "just a type alias" case of this syntax, which appears to be what you're specifically asking about. I don't know what the status of that is, but I wouldn't be surprised if it's also simply waiting on all of the other fundamental work to reach a tipping point.
Unfortunately there’s no syntax for this other than writing out the -> impl Future return type, async fn always capture all arguments even if they’re unused.
trait A {
type Output: ToString;
fn a() -> Self::Output;
}
trait B {
fn b() -> impl ToString;
}
fn foo<T: A, U: B>()
where
T::Output: Send;
// you can't constrain the return type of U::b() here!
That's right, but I'm pretty sure you can still do something like this (not tested):
fn foo<T: A, U: B>()
where
<T::b as Fn() -> _>::Output: Send;
And with GAT, it would be easier to extract the return type of function. C++ is using that kind of tricks since ages, so I don't see why it wouldn't be possible to implement them in Rust (those tricks may requires GATs however).
fn foo<T: Foo, U>(_: T)
where
T::b: Fn() -> U,
U: Send
(Since Fn::Output is unstable, and you can't have placeholders inside type bounds). Doesn't work currently because b doesn't exist in the associated type namespace, and as far as I know there is no way to reference the type of the associated function. So would need at least an additional new feature to support that somehow.
(And note that it can't just be to introduce associated functions directly into the type namespace too, trait Foo { type bar; fn bar(); } is valid).