rusttraitscommutativity

Require commutative operation in Rust trait bound


Suppose I have a group of related non-scalar structs with a commutative arithmetic operation defined on them. For example,

struct Foo {
    a: f64,
    b: f64
}

impl Add<f64> for Foo {
    type Output = Foo;
    
    fn add(self, v: f64) -> Self::Output {
        Foo {
            a: self.a + v,
            b: self.b + v
        }
    }
}

impl Add<Foo> for f64 {
    type Output = Foo;
    
    fn add(self, foo: Foo) -> Self::Output {
        Foo {
            a: foo.a + self,
            b: foo.b + self
        }
    }
}

I want to implement a trait on this group of structs, taking advantage of this operation. That is, I want something like the following:

trait Bar: Add<f64, Output = Self> + Sized {
    fn right_add(self, f: f64) -> Self {
        self + f
    }
    
    // Doesn't compile!
    fn left_add(self, f: f64) -> Self {
        f + self
    }
}

However, this currently doesn't compile, since the super-trait bound doesn't include the left addition of f64 to Self. My question is: How can I state this commutative trait bound?

(Playground link.)

Edit: To be clear, I'm aware that right_add and left_add have the same output. I'm mainly interested in the ergonomics of not having to remember which is "correct" according to the compiler. In addition, I'm curious to learn how to do this, even if it's not strictly necessary.


Solution

  • Inverted trait bounds like this are the exact usecase for where syntax:

    trait Bar
    where
        f64: Add<Self, Output = Self>,
        Self: Add<f64, Output = Self> + Sized,
    {
        fn right_add(self, f: f64) -> Self {
            self + f
        }
    
        fn left_add(self, f: f64) -> Self {
            f + self
        }
    }
    

    Playground link