Description
I was surprised to learn that the implementation of core::ops::{Add, Mul}
(keywords: addition, multiplication) is not automatically (and exclusively) commutative. This is often not a problem for cases where it is possible to both impl Mul<X> for Y
and impl Mul<Y> for X
, but this is not an option when generics are involved.
For example, this implementation of Mul
allows multiplying Size
by any basic number type (from num_traits
), as in Size(12) * 2
or Size(42) * 1.0
:
impl<T, U> Mul<U> for &Size<T>
where
T: ToPrimitive,
U: ToPrimitive
{
type Output = Size<u64>;
fn mul(self, other: U) -> Self::Output {
// omitted
}
}
but it is not possible to define an ergonomic and efficient inverse to support the commutative variant of the same operations (2 * Size(12)
or 3.0 * Size(7)
), because the following is illegal:
impl<T> Mul<Size<T>> for ToPrimitive
where
T: ToPrimitive,
{
type Output = Size<u64>;
fn mul(self, other: Size<T>) -> Self::Output {
Size::Bytes((self as u64 * other.bytes()) as u64)
}
}
as the self
parameter to the mul
function results in an attempt to define a non-generic parameter with unknown size.
I would like to use this issue to sound out ideas to support commutative operations, at the very least for operations that are typically (read: mathematically) commutative, but would appreciate any insight or commentary that sheds light on anything I'm missing here first.