Search code examples
rustoperatorstraitsassignment-operator

Should I implement AddAssign on a newtype?


I've got a newtype:

struct NanoSecond(u64);

I want to implement addition for this. (I'm actually using derive_more, but here's an MCVE.)

impl Add for NanoSecond {
    fn add(self, other: Self) -> Self {
        self.0 + other.0
    }
}

But should I implement AddAssign? Is it required for this to work?

let mut x: NanoSecond = 0.to();
let y: NanoSecond = 5.to();
x += y;

Will implementing it cause unexpected effects?


Solution

  • Implementing AddAssign is indeed required for the += operator to work.

    The decision of whether to implement this trait will depend greatly on the actual type and kind of semantics that you are aiming for. This applies to any type of your own making, including newtypes. The most important prior is predictability: an implementation should behave as expected from the same mathematical operation. In this case, considering that the addition through Add is already well defined for that type, and nothing stops you from implementing the equivalent operation in-place, then adding an impl of AddAssign like so is the most predictable thing to do.

    impl AddAssign for NanoSecond {
        fn add_assign(&mut self, other: Self) {
            self.0 += other.0
        }
    }
    

    One may also choose to provide additional implementations for reference types as the second operand (e.g. Add<&'a Self> and AddAssign<&'a Self>).

    Note that Clippy has lints which check whether the implementation of the arithmetic operation is sound (suspicious_arithmetic_impl and suspicious_op_assign_impl). As part of being predictable, the trait should behave pretty much like the respective mathematical operation, regardless of whether + or += was used. To the best of my knowledge though, there is currently no lint or API guideline suggesting to implement -Assign traits alongside the respective operation.