Implementing generic trait with local struct on local trait

Hi!

I encountered a problem, which I know has currently no solution, but I wanted help understanding why it's not allowed. I have a struct Vector, which is a 2D vector, and a trait Scalar, which is implemented on e.g. f32. I want to be able to multiply a scalar by a vector, by implementing std::ops::Mul<Vector> on Scalar:

struct Vector {
    pub x: f32,
    pub y: f32,
}

impl Vector {
    fn new(x: f32, y: f32) -> Self {
        Vector { x, y }
    }
}

trait Scalar {
    fn to_float(self) -> f32;
}

// Vector-by-Scalar.  This works
impl<T: Scalar> std::ops::Mul<T> for Vector
{
    type Output = Vector;

    fn mul(self, rhs: T) -> Vector {
        let rhs = rhs.to_float();
        Vector::new(self.x * rhs, self.y * rhs)
    }
}

// Scalar-by-Vector.  This is not permitted
impl<T: Scalar> std::ops::Mul<Vector> for T
{
    type Output = Vector;

    fn mul(self, rhs: Vector) -> Vector {
        let lhs = self.to_float();
        Vector::new(lhs * rhs.x, lhs * rhs.y)
    }
}

When checking, I'm getting the following error:

error[E0210]: type parameter `T` must be used as the type parameter for some local type (e.g. `MyStruct<T>`)                                                                                          
  --> src/main.rs:28:1                                                                                                                                                                                
   |                                                                                                                                                                                                  
28 | impl<T: Scalar> std::ops::Mul<Vector> for T                                                                                                                                                      
   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type parameter `T` must be used as the type parameter for some local type                                                                            
   |                                                                                                                                                                                                  
   = note: only traits defined in the current crate can be implemented for a type parameter

Now, I found a thread that tells me I can't implement, say, Display on Scalar, and I understand why: Display is defined outside the local crate. However, here, I want to implement Mul<Vector>, which is a generic trait parameterized by a local struct. In a sense, Mul<Vector> is itself akin to a local trait, right? Then, why is this not authorized?

Thank you very much for your time!

This is the type of thing the following RFC attempts to allow (or fix, depending on your perspective):
https://github.com/rust-lang/rfcs/pull/2451

1 Like

Alright, that answers my question. Thanks a lot!