Issues with generics

i have a situation along the line of

impl<A> Trait1 for A{
       fn myfunc(&mut self){
             .................
             <A as Trait2>::fn(self) //if and only if A:Trait2
             .................
       }
}

i think i can probably find a workaround to do that but i was wondering if anyone knows of a clean maintainable solution for something like this ideally without runtime costs

You can add a requirement that the trait is implemented:

impl<A: Trait2> Trait1 for A {
1 Like

yeah but that's not the problem, what i want is to reuse the rest of the function for instances where A is not Trait2 and also avoid conflicts from overlapping impls

I think OP wants something like conditional bounds, or specialization, guessing from the comment "if and only if ...".

if I understand your question correctly, here, by "runtime costs", you probably mean something like trait object downcasting, or TypeId checking?

the "cleanest" solution would be specialization, but it's an incomplete feature and doesn't work well. a working subset is called min_specialization, but it's also nightly only.

if Trait2 is dyn-compatible, I think the IDET pattern might be a "not so clean" workaround, see:

It's not possible to write an if condition along the lines of "If trait is implemented, do this" in Rust, unfortunately.

2 Likes

The only workaround I know is to create empty default for Trait2 (for things which are not really Trait2) and declare the real implementation for things which are real Trait2.

Like this, the bound for Trait2 is always true and the function can always call the Trait2 methods.

fn main() {
    let mut trait2 = Trait2Struct {};
    trait2.myfunc();

    let mut nottrait2 = NoTrait2Struct {};
    nottrait2.myfunc();
}

pub trait Trait2 {
    fn specific(&mut self) {}
}

struct Trait2Struct {}

impl Trait2 for Trait2Struct {
    fn specific(&mut self) {
        println!("Trait2Struct");
    }
}

struct NoTrait2Struct {}

impl Trait2 for NoTrait2Struct {}

pub trait Trait1 {
    fn myfunc(&mut self);
}

impl<A> Trait1 for A
where
    A: Trait2,
{
    fn myfunc(&mut self) {
        println!("myfunc start");
        A::specific(self);
        println!("myfunc end");
    }
}


The drawback : you have to impl (empty or real) Trait2 for all the struct which will impl Trait1.

1 Like