2

Is there a good way to combine all operator overloading combinations into a single trait in Rust? As discussed, in the question How to implement idiomatic operator overloading for values and references in Rust?, there are four different combinations for operator overloading binary operators: (ref,ref), (ref,val), (val,ref), and (val,val). Further, there's a number of macros and such for helping define these routines. My question is how to require all of these combinations in a sane way through a trait or another mechanism. Consider the following code that attempts to create an algebra for a general float/real type:

// Create some random type that we want to represent as a Real
#[derive(Debug,Clone)]
struct Foo <Real> {
    x : Real,
    y : Real,
}

// Add the algebra for Foo
impl <Real> std::ops::Add <&'_ Foo<Real>> for &'_ Foo <Real>
where
    for <'a> &'a Real : std::ops::Add<&'a Real,Output=Real>
{
    type Output = Foo <Real>;
    fn add(self, other : &'_ Foo <Real>) -> Self::Output {
        Foo {
            x : &self.x + &other.x,
            y : &self.y + &other.y,
        }
    }
}
impl <Real> std::ops::Add <Foo<Real>> for &'_ Foo <Real>
where
    for <'a> &'a Real : std::ops::Add<Real,Output=Real>
{
    type Output = Foo <Real>;
    fn add(self, other : Foo <Real>) -> Self::Output {
        Foo {
            x : &self.x + other.x,
            y : &self.y + other.y,
        }
    }
}
impl <Real> std::ops::Add <&'_ Foo<Real>> for Foo <Real>
where
    for <'a> Real : std::ops::Add<&'a Real,Output=Real>
{
    type Output = Foo <Real>;
    fn add(self, other : &'_ Foo <Real>) -> Self::Output {
        Foo {
            x : self.x + &other.x,
            y : self.y + &other.y,
        }
    }
}
impl <Real> std::ops::Add <Foo<Real>> for Foo <Real>
where
    Real : std::ops::Add<Real,Output=Real>
{
    type Output = Foo <Real>;
    fn add(self, other : Foo <Real>) -> Self::Output {
        Foo {
            x : self.x + other.x,
            y : self.y + other.y,
        }
    }
}

// Compute a function on a slice of Reals.  This should work for f64 and Foo <f64>
fn foo <Real> (x : &[Real]) -> Real
where
    for <'a> &'a Real :
        std::ops::Add<&'a Real,Output=Real> +
        std::ops::Add<Real,Output=Real> +
        Clone,
    for <'a> Real :
        std::ops::Add<&'a Real,Output=Real> +
        std::ops::Add<Real,Output=Real> +
        Clone,
    Real : Clone
{
    (&x[0]+x[1].clone())+&x[2]
}

// Run foo on two different types
fn main() {
    let x = vec![1.2,2.3,3.4];
    let _x = foo::<f64>(&x);
    println!("{:?}",_x);
    let y : Vec <Foo<f64>>= x.into_iter().map(|z|Foo{x:z,y:z+1.0}).collect();
    let _y = foo::<Foo<f64>>(&y);
    println!("{:?}",_y);
}

The routine foo places a requirement both on Real and its reference for <'a> &'a Real to complete the algebra. Now, this is pretty verbose and will only get worse as we add Mul, Div, etc. I'd like to either have a single trait for Real or at least a single trait for Real and for <'a> &'a Real. That said, I can't quite figure out a definition for it. Typically, I'd place all of the definitions in a new trait such as:

trait MyFloat :        
    std::ops::Add <REFSELF,Output = NOREFSELF> +
    std::ops::Add <NOREFSELF,Output = NOREFSELF>
where
    Self : std::marker::Sized,
{}                                                  
impl <T> MyFloat for T where T:         
    std::ops::Add <REFSELF,Output = NOREFSELF> +
    std::ops::Add <NOREFSELF,Output = NOREFSELF>          
{} 

But, this is already getting odd. We need the output to always be the non-reference form of the type and we want the right hand side to be either the reference form or the non-reference form of the type. However, as far as I know, there's not a mechanism for achieving this by manipulating Self.

Is there a good way for combining these definitions into a single trait?

wyer33
  • 6,060
  • 4
  • 23
  • 53
  • that what [`num`](https://github.com/rust-num/num) is for – Stargateur Sep 12 '19 at 18:23
  • @Stargateur Unless I'm missing something, num covers the (val,val) situation and then relies on the `Copy` trait. Which trait allows all of the different combinations of ref or not? – wyer33 Sep 12 '19 at 19:14

0 Answers0