Traits and typing question

Hi there! I can't get this to work and I'm not sure if it is even technically possible.

(playground: Rust Playground)

I have a struct generic over a number of traits and I want to choose the implementation of each trait based on conditions.

In pseudo code I want to do something like the following (I KNOW IT DOESN'T COMPILE ;-)):

trait MyTrait {
    fn do_it(&self);
}

struct TraitImplOne {}
impl MyTrait for TraitImplOne {
    fn do_it(&self) {
        println!("one");
    }
}

struct TraitImplTwo {}
impl MyTrait for TraitImplTwo {
    fn do_it(&self) {
        println!("two");
    }
}

struct Receiver<T>
where
    T: MyTrait,
{
    t: T,
}

fn main() {
    let a = choose_trait();
    let receiver = Receiver { t: a };
    receiver.t.do_it();
}

fn choose_trait() -> Box<dyn MyTrait> {
    if 1 == 0 {
        TraitImplOne {}
    } else {
        TraitImplTwo {}
    }
}

Is this possible? I mean, the compiler has all the information it wants - it knows the possible combinations of implementations so it can go ahead and generate the various code for static dispatch, but I can't get it to compile.

I was surprised to find out that the trait can be "inferred" (probably wrong word), which gave me some hope:

fn main() {
    let a = TraitImplOne {};
    let receiver = Receiver { t: a };
    receiver.t.do_it();
}

The reason I don't want to Box the traits is for performance - this is a hot path.

Is this possible?

Thanks!

The word "conditions" is carrying a lot of weight here. You can certainly choose the implementation based on compile time conditions.

But if tests a condition at runtime, not at compile time.

Obviously if the only condition you care about is 1 == 0 then you can just remove it entirely. But that presumably isn't what you're looking for. So, what conditions?

1 Like

Yeah, unfortunately the "conditions" are based on runtime information.

I'd hoped the fact that the outcomes were all known at compile time (even if the determination of which outcomes should be used isn't known until runtime) would allow me to proceed.

EDIT: specifically, at runtime a "Plan" is provided and my code reduces the plan to a bunch of strategies. Those strategies are the traits.

The enum_dispatch crate may help you approach the level of convenience you were hoping for.

Note how it works - you create an enum that contains all the different types you might want to use, the crate ~magically implements the trait for it, and when you call trait methods on the enum it dispatches the calls at runtime (though not through a vtable - it's still "dynamically dispatched", just more efficiently than dyn Trait).

There has been some talk of auto-generated sum types which would basically be this as a built-in feature, but it didn't get much traction (unless I've missed a more recent RFC).

3 Likes