How can an operator be overloaded for different RHS types and return values?

operator-overloading, rust

Solution

At the moment only a single `impl` is allowed per trait-type pair.

This situation will be improved with RFC 48, but it's not the full story (it's not really any of the story). The relevant section is Coherence, and it certainly doesn't mention the operator overloading case specifically, and essentially says it is still illegal:

The following example is NOT OK:

trait Iterator<E> { ... }
impl Iterator<char> for ~str  { ... }
impl Iterator<u8> for ~str { ... }

Niko Matsakis (author of that RFC & Rust-type-system expert) has been thinking about these overloading traits specifically: he is the one who published ("What if I want overloading?") the trick below, but he has expressed his distaste towards it, mentioning that he'd like to allow implementations as you have written...

... which is where his RFC 135 comes in. The situation is described in detail in "multidispatch traits".

You can work-around it for now using secondary traits. The extra layer of traits allows you to write just one `impl Mul<...> for Vector3D` but comes at the cost of requiring a new trait for each type for which you wish to have multiple implementations of `Mul`.

#[deriving(Show)]
struct Vector3D {
    x: f32,
    y: f32,
    z: f32
}

trait MulVec3D<Res> {
    fn do_mul(&self, v: &Vector3D) -> Res;
}

// Multiplication with scalar
impl MulVec3D<Vector3D> for f32 {
   fn do_mul(&self, v: &Vector3D) -> Vector3D {
       Vector3D {x: v.x * *self, y: v.y * *self, z: v.z * *self} 
   }
}
// Multiplication with vector, aka dot product
impl MulVec3D<f32> for Vector3D {
    fn do_mul(&self, v: &Vector3D) -> f32 {
        self.x * v.x + self.y * v.y + self.z * v.z
    }
}

impl<Res, RHS: MulVec3D<Res>>  Mul<RHS, Res> for Vector3D {
    fn mul(&self, rhs: &RHS) -> Res {
        rhs.do_mul(self)
    }   
}

fn main() {
    let a = Vector3D { x: 1.0, y: 2.0, z: 3.0 };
    let b = Vector3D { x: -3.0, y: 2.0, z: -1.0 };

    println!("{}, {}", a * 2f32, a * b); // Vector3D { x: 2, y: 4, z: 6 }, -2
}

Problem

Given the following struct: ``` struct Vector3D { x: f32, y: f32, z: f32 } ``` I want to overload its `*` operator to do a dot product when the right hand side is a `Vector3D`, and to do an element-wise multiplication when the RHS is a `f32`. My code looks like this: ``` // Multiplication with scalar impl Mul<f32, Vector3D> for Vector3D { fn mul(&self, f: &f32) -> Vector3D { Vector3D {x: self.x * *f, y: self.y * *f, z: self.z * *f} } } // Multiplication with vector, aka dot product impl Mul<Vector3D, f32> for Vector3D { fn mul(&self, other: &Vector3D) -> f32 { self.x * other.x + self.y * other.y + self.z * other.z } } ``` The compiler says for the first impl block: ``` Vector3D.rs:40:1: 44:2 error: conflicting implementations for trait `std::ops::Mul` Vector3D.rs:40 impl Mul<f32, Vector3D> for Vector3D { ... Vector3D.rs:53:1: 57:2 note: note conflicting implementation here Vector3D.rs:53 impl Mul<Vector3D, f32> for Vector3D { ... ``` and vice versa for the other implementation.

Original source

Related problems