Multiple default implementations of a trait


#1

Lets say I have some trait Foo which I would like to implement for many types. Many of the types I need to implement it for can reuse the same implementation. What I would like is to be able to write each different implementation once, then simply list all the types which use that implementation. Each of the types should then implicitly implement Foo. I know I can do it like this, but is there a cleaner way?

    trait Foo {
        fn a();
        fn b();
    }
    trait FooImpl1 {
        fn a() { ... }
        fn b() { ... }
    }
    trait FooImpl2 {
        fn a() { ... }
        fn b() { ... }
    }
    impl<T: FooImpl1> Foo for T {
        fn a() { <T as FooImpl1>::a() }
        fn b() { <T as FooImpl1>::b() }
    }
    impl<T: FooImpl2> Foo for T {
        fn a() { <T as FooImpl2>::a() }
        fn b() { <T as FooImpl2>::b() }
    }
    impl FooImpl1 for T1 { }
    impl FooImpl1 for T2 { }
    impl FooImpl2 for T3 { }
    impl FooImpl2 for T4 { }

#2

What you have won’t work because rust will consider your two Foo impls, one for FooImpl1 and the other for FooImpl2 as conflicting. And that makes sense - what if T implements both - it’s ambiguous which to pick.

I think generally speaking folks reach for macros to reduce the boilerplate of implementing the traits in a similar manner for many types.


#3

Oh, you’re right! I had extra constraints on my impls which I didn’t realize were factoring into the impl resolution.


#4

I usually do this as well. A prime example is where you want something which can work with all the various integer types, or if you are doing a bunch of trivial Add or Sub impls.

std uses macros to abstract away all the boilerplate for integer conversions. Check out their impl_from macro if you want a concrete example.