Trait return impl of trait

I'm looking to do something like the following (simplified example):

pub trait MyTrait {}

struct MyStruct;

impl MyTrait for MyStruct {}

pub trait AnotherTrait where
{
    fn f(self) -> MyTrait;
}

struct AnotherStruct;

impl AnotherTrait for AnotherStruct {
    fn f(self) -> MyStruct {

    }
}

I think this should be a reasonable thing to do. If I call f(T) where say T : MyTrait and I don't know anything else about it, then all I know about the result is that it implements AnotherTrait which is fair enough. But as traits are all resolved at compile time (as far as I understand) when the code is compiled the compiler will know the exact type f is called with each time so will then also know the result type of f and hence be able to reserve the appropriate amount of stack space.

I just don't know how to write in a function in a trait? Any ideas or is there a reason why allowing this isn't sensible (an example to illustrate why the compiler could deal with this would be great because in this case it's obvious I'm completely missing something).

If I understand correctly, you're trying to associate a type that implements MyTrait to each type that implements AnotherTrait. The issue is that traits aren't really types, so you have to pick a type that implements AnotherTrait to let the compiler resolve the types of things.

Fortunately, Rust has a feature for precisely what you want: associated types. In your example, it would be like this.

It is impossible for now, because of some internal type elision stuff. What you are actually trying to do is:

pub trait MyTrait {}

struct MyStruct;

impl MyTrait for MyStruct {}

pub trait AnotherTrait where
{
  type Output: MyTrait;
  fn f(self) -> Output;
}

struct AnotherStruct;

impl AnotherTrait for AnotherStruct {
  type Output = MyStruct;
  fn f(self) -> MyStruct { ... }
}

The actual reason is unability to elide actual type for fn f(self) -> impl MyTrait - it is needed for impl Trait to immediately elide type by function body. By creating dependent type, you are giving hint, that the type would be specified later, and possibly adding it some additional bounds. Many people would like impl Trait on return position in Trait functions to behave like syntax sugar for this (creating dummy dependent type), but for now it's not.

1 Like

You "this" link is broken could you please repost?

Sorry about that. I posted it from my phone and the link didn't copy right. I've edited the post with the right link. The code is substantially the same as what @hashedone posted anyway.

As @hashedone pointed out, the definition of AnotherTrait must use an associated type parameter, on which you can put a trait bound:

pub
trait MyTrait {}

pub
trait AnotherTrait {
    type F_Output : MyTrait;

    fn f (self) -> Self::F_Output
    ;
}

This can be problematic when implementing AnotherTrait, since now you need to name the F_Output type, which, for instance, cannot be done when dealing with closures or function items.

One can, however, get pretty close to -> impl MyTrait notation, and be able to use ineffable / voldemort types such as closures', thanks to the unstable / nightly-only type_alias_impl_trait feature:

#![feature(type_alias_impl_trait)]

impl AnotherTrait for () {
    fn f (self)
      // -> impl MyTrait /* Does not work within a trait */
      -> Self::F_Output
    {
        // By defining `MyStruct` within a function's body, it 
        // becomes ineffable outside it
        struct MyStruct;
        impl MyTrait for MyStruct {}

        MyStruct
    }

    // Cannot use MyStruct here since its definition is private to the
    // scope of `f`'s body, but with `type_alias_impl_trait` feature
    // we can define an existential type for this `impl AnotherTrait` block
    type F_Output = impl MyTrait;
}
1 Like

It's important to note that that is an associated type. A dependent type is something very different, and is a much more advanced feature that most programming languages (and every mainstream programming language) to date don't offer.

1 Like

True, misswrote. I though about associated type.