Hello everyone,
it's probably easier to show example code than to explain.
trait Foo {}
trait Bar {
fn bar(&self) {
println!("bar");
}
}
struct FooStruct<T>(T);
impl<T> Foo for FooStruct<T> {}
impl<T: Bar> Bar for FooStruct<T> {}
trait Baz {
fn foo(self) -> impl Foo where Self: Sized {
FooStruct(self)
}
}
impl Bar for i32 {
}
impl Baz for i32 {
}
impl<'a> Foo for & 'a str {
}
impl<'a> Baz for & 'a str {
#[allow(refining_impl_trait)]
fn foo(self) -> Self {
self
}
}
fn main() {
0.foo();
0.bar();
"0".foo();
FooStruct(0).bar();
// 0.foo().bar();
}
I want a trait with a default method that isn't fixed to a particular concrete return type, and that doesn't require implementing a particular trait, but that will pass through implementations of that trait when they exist. Is there a way to achieve this?
In the example I'm looking for a way to make the commented out line compile without changing the Baz implementations for i32
or & 'a str
.
Ways I could imagine it working but that seem not to be allowed include separate signatures for the method as must be implemented by implementing types and for the default method with the default impl being a refining impl (so that it can return FooStruct), an associated type with a default that is the return value of the method (and implementing types being forced to keep them in sync), specialization on whether Self implements Bar, and conditional constraints on the return type (something like impl Foo + for<Self: Bar> Bar
).
Is there some reasonable workaround that does work?