Trait Objects with Associated Types part 2


#1

I saw this thread Trait objects with associated types

It is very close to what I was hoping to do.

My goal is to have a trait with an associated type, and a wrapper trait so that I can create a heterogeneous list. However I want the heterogeneous list to have a function that could return different types. The reason being that the code I am writing interfaces with a graphics system so when I get the various interal trait objects and use them, as a programmer I know I have the correct types. The question lies in whether or not there is a way to get the compiler to believe me.

The difference though is that in the previous thread the wrapper trait’s function doit is of type Self -> String. Is it possible to make a wrapper trait that returns a non concrete type. It doesn’t seem like this is possible but I would be curious to know.


#2

What type would you want to return? The associated type presumably? If so, I’m not aware of any good pleasing way to accomplish this. Here’s something I hacked up using Any but it’s not something I would build a system on top of :slight_smile::

use std::any::Any;

trait MyTrait {
    type Assoc: Any;

    fn get(&self) -> &Self::Assoc;
}

struct Foo;
impl MyTrait for Foo {
    type Assoc = i32;

    fn get(&self) -> &i32 {
        &5
    }
}

struct Bar;
impl MyTrait for Bar {
    type Assoc = &'static str;

    fn get(&self) -> &Self::Assoc {
        &"hello"
    }
}

trait Erased {
    fn get(&self) -> &Any;
}

impl<M, A: 'static> Erased for M
where
    M: MyTrait<Assoc = A>,
{
    fn get(&self) -> &Any {
        self.get() as &Any
    }
}

fn main() {
    let v: Vec<Box<Erased>> = vec![Box::new(Foo), Box::new(Bar)];
    let x: &i32 = v[0].get().downcast_ref().unwrap();
    println!("{}", x);
    let y: &&str = v[1].get().downcast_ref().unwrap();
    println!("{}", y);
}

If you can unify all the associated types to some common trait that they impl, you can remove the Any bit in favor of a normal trait object. Alternatively, perhaps you can redesign things so that you don’t need to expose the associated type like this at all.

Have you considered using an enum instead of trait objects?

Anyway, if you elaborate some more on your scenario there might be better suggestions.


#3

Thank you for the thoughtful reply. As I suspected there is just a flaw in the way I’m attempting to model my problem and further research shows most people take a different approach.