How to have multiple implementations depending on type of generic

Hi, I'm still rather a newbie to Rust. How can I have a default implementation of a trait function that can be overridden only if a generic type of the implementing type supports another trait?

trait Trait {
    fn inc(&self);
    fn rem(&self) {
        println!("nope");
    }
}

#[derive(Debug, Clone, PartialEq, Eq)]
struct Foo<T> {
    i: T,
}

impl<T> Trait for Foo<T>
where
    T: Copy
        + Display
        + PartialEq
        + Add<u64, Output = T>,
{
    fn inc(&self) {
        println!("{}", self.i + 1);
    }
}

/*
impl<T> Trait for Foo<T>
where
    T: Copy
        + Display
        + PartialEq
        + Rem<u64, Output = u64>,
{
    fn rem(&self) {
        println!("{}", self.i % 2u64);
    }
}
*/

fn main() {
    let a = Foo { i: 1 };
    a.inc();
    a.rem();
}

I want to write the commented out code, but it doesn't compile (conflicting implementation). Alternatively, I can move fn rem to the other impl block, but that requires adding the Rem bound, which I don't want to do.

I want to use the default implementation from the trait if T doesn't support Rem, but if it does, I want to provide a different implementation. Suggestions?

not sure how to interpret your intention here, but if you want trait method always defined, and want to provide generic implementations based on trait bounds, I think you need specialization, which is very experimental currently and problematic.

on the other hand, if the method only makes sense for certain Self types, you can put the requirement as trait bound at the method declaration, and with a default implementation, something like this:

trait Trait {
    fn inc(&self);
    fn rem(&self)
    where
        Self: Copy + Display + PartialEq + Rem<u64, Output = u64>,
    {
        println!("{}", self % 2u64);
    }
}

please note, default implementation and generic implementation are very different, default implementation of a method must be defined within the trait definition itself. implementers can "override" the default implementation. generic implementation is just implementer for some generic type, they cannot be "override", and concrete types could conflict with generic implementation if the trait bounds is not carefully chosen.

You may be better off using a macro to define the trait in two different ways for an explicit set of types.

1 Like

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.