Generic trait that returns another version of the trait without using boxed

I want to create a trait that returns a different implementation of the trait in functions something like this:

trait Interface {
    type Item;
    fn transform<E, U:Interface<Item=E>>(&self,e: E) -> U;
}

struct Foo<T> {
    t:T
}

impl <T: Send> Interface for Foo<T> {
    type Item = T;

    fn transform<E, U:Interface<Item=E>>(&self,e: E) -> U {
        Foo{ t: e}
    }
}

As far as I can tell it should be possible, because when implementing the interface the types are known, but unfortunately I am getting

error[E0308]: mismatched types
  --> src/mod.rs:42:9
   |
41 |     fn transform<E, U:Interface<Item=E>>(&self,e: E) -> U {
   |                                                         - expected `U` because of return type
42 |         Foo{ t: e}
   |         ^^^^^^^^^^ expected type parameter, found struct `Foo`
   |
   = note: expected type `U`
              found type `Foo<E>`
   = help: type parameters must be constrained to match other types
   = note: for more information, visit https://doc.rust-lang.org/book/ch10-02-traits.html#traits-as-parameters

error: aborting due to previous error

Which makes no sense to me because U is Foo<E> which satisfies its conditions.

Am I doing wrong and is this possible at all in Rust?

Type parameters are chosen by the caller not the function body.

Alternate is (could use with 'static instead.)

trait Interface {
    type Item;
    fn transform<'a, E:'a>(&self,e: E) -> Box<dyn Interface<Item=E> + 'a>;
}

Thank you for your response. I was kind of looking for a version that does not use the Box type, just generics.

Afraid it isn't possible currently. The proposal of GAT's is far from being in a working state.

I have a "workaround". Because the type parameter is chosen by the caller you can just route the function calls:

trait Interface {
    type Item;

    fn new(e :Self::Item) -> Self;
    fn transform<E, U:Interface<Item=E>>(&self,e: E) -> U;
}

struct Foo<T> {
    t:T
}

impl <T: Send> Interface for Foo<T> {
    type Item = T;

    fn new(e: Self::Item) -> Foo<T> {
        Foo{t: e}
    }
    fn transform<E, U:Interface<Item=E>>(&self,e: E) -> U {
       U::new(e)
    }
}

Seems to work. Thoughts?

That does switch it to callers choice. Up to you if you want the function working that way. It is far more likely to fail automatic type inference.

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.