I am trying to make a library that can be used with various primitive numeric types, but I'm having some trouble getting some of the overloads to work. (see the attached playground for a minimal code example)
See E0210 and E0117
I can see that the orphan rules for rust are being violated by my code example, but I don't understand why this is considered a 'bad thing' in this case.
It seems like making a plus operator would allow one to create one that respects the commutative rule, but due to the inherently ordered nature of operator overloads, am I simply not able to?
I would like to find a way to get a reversed plus operator overload (ie allow MyType + i32
and i32 + MyType
to both be valid and both return MyType. If this is not possible then I will just have to make that concession.
This post on stack overflow seems to explain the issue pretty well and offer a workaround that sort of worked (in that it allowed the overload to compile, but didn't allow the reversed operator overload to function correctly)
I saw here that it's not possible to work around this issue, but I'm neither confident in nor surprised at this conclusion.
#![allow(unused)]
use std::ops;
struct MyType {
val: i32,
}
trait SupportedType<T> {
fn as_my_type(val: T) -> MyType;
}
impl SupportedType<i32> for i32 {
fn as_my_type(val: Self) -> MyType {
MyType { val: val }
}
}
impl ops::Add<MyType> for MyType {
type Output = MyType;
fn add(self, val: MyType) -> Self::Output {
MyType { val: self.val + val.val }
}
}
// Works
impl<T: SupportedType<T>> ops::Add<T> for MyType where T: SupportedType<T> {
type Output = MyType;
fn add(self: MyType, val: T) -> Self::Output {
self + T::as_my_type(val)
}
}
// Doesn't work
impl<T: SupportedType<T>> ops::Add<MyType> for T where T: SupportedType<T> {
type Output = MyType;
fn add(self, val: T) -> Self::Output {
self + T::as_my_type(val)
}
}
fn main() {
let my_val: MyType = MyType { val: 42 };
let the_chosen_one: i32 = 21;
// Works: uses the first one
assert_eq!((my_val + the_chosen_one).val, 63);
// Doesn't work: uses the second one
assert_eq!((the_chosen_one + my_val).val, 63);
}
You can do that only with concrete types. Doing that generically, as you've tried, is impossible.