0

I have a trait like this:

use std::ops::Add;

pub trait GroupElement: Clone + Sized {
    fn plus(&self, b: &Self) -> Self;
}

#[derive(Debug)]
struct G1 {
    value: i32,
}

#[derive(Debug)]
struct G2 {
    value: i32,
}

impl GroupElement for G1 {
    fn plus(&self, b: &Self) -> Self {
        let value = self.value + b.value;
        G1 { value }
    }
}

impl GroupElement for G2 {
    fn plus(&self, b: &Self) -> Self {
        let value = self.value + b.value;
        G2 { value }
    }
}

Now if I wanted to overload the + operator without code duplication I could use a macro to implement the Add trait like this

impl Add for $group_element {
    type Output = Self;

    fn add(self, other: Self) -> Self {
        self.plus(&other)
    }
}

But I want to implement Add for the trait GroupElement so that I can use the generic functions over GroupElement by using the + operator.

impl<T: GroupElement> Add<T> for GroupElement {
    type Output = Self;

    fn add(self, other: T) -> Self {
        self.plus(&other)
    }
}

Above code comlains about GroupElement not having a known size at compile time which I agree with, different groups will have different sizes.

I tried the following code

impl<T: GroupElement> Add<T> for T {
    type Output = T;

    fn add(self, other: T) -> T {
        self.plus(&other)
    }
}

I get error with message type parameter `T` must be used as the type parameter for some local type which seems incorrect since GroupElement is local to my crate.

How should I solve this? The actual implementation of GroupElement is here. Links to G1 and G2.

Stargateur
  • 24,473
  • 8
  • 65
  • 91
lovesh
  • 5,235
  • 9
  • 62
  • 93
  • 1
    [Related](https://stackoverflow.com/questions/29256519/i-implemented-a-trait-for-another-trait-but-cannot-call-methods-from-both-traits). But it seems like you already figured out how to correctly do that. The problem here seems to stem from *orphan rules*. This might be a term to search for. – Lukas Kalbertodt Aug 08 '19 at 09:52
  • @LukasKalbertodt The orphan rule applies when the trait and type are in different crates which is not the case here. – lovesh Aug 08 '19 at 10:02
  • 1
    That is the case here as you implement `for T` which could be any type. Yes, the type has to implement `GroupElement` (which is from your crate), but people could depend on your crate and implement `GroupElement` for their types. So indeed orphan rules are the problem here. But I understand why it doesn't seem like a problem (especially so if `GroupElement` is private or your crate is an executable). [This RFC](https://github.com/rust-lang/rfcs/blob/master/text/2451-re-rebalancing-coherence.md) which relaxes the rules a bit could help you, but I'm not sure. – Lukas Kalbertodt Aug 08 '19 at 10:08
  • @LukasKalbertodt Thanks. That makes sense. – lovesh Aug 08 '19 at 10:31
  • Well, you can always do it with a macro. The syntax in `impl Add for $group_element` even looks like one (due to the `$`)… – Jan Hudec Aug 08 '19 at 15:33

0 Answers0