Assigning 'new' Self vs modifying existing self (AddAssign)

Hi there,
I am quite new to Rust and currently just playing with a little project.
As I needed to implement the AddAssign Trait, I went to the docs and the example AddAssign in std::ops - Rust made me wondering why it is implemented like this

*self = Self {
            x: self.x + other.x,
            y: self.y + other.y,
}

instead of

// just for cases where this is possible of course, like f64
self.x += other.x;
self.y += other.y;

Is there any reason or benefit why you would assign a "new" Self to the *self?
Or maybe I just don't understand t correctly :sweat_smile:

No, and I think that the example is kinda silly here. Either version does the exact same thing.

1 Like

I suppose one advantage is that if you add a third field z to your point type, then the *self = Self { ... } version would not compile until you update it to also change the z field, whereas the self.x += other.x version would not remind you of this.

5 Likes

Right!
That makes sense, haven't thought about that case.
Thank you :raised_hands:

1 Like

When manually implementing things like Debug or PartialEq I will destructure my type for exactly this reason. As long as you don't use .. the compiler will make sure you don't forget to update your code.

struct Point {
  x: f32,
  y: f32,
}

impl Debug for Point {
  fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
    let Point { x, y } = self;
    f.debug_struct("Point").field("x", x).field("y", y).finish()
  }
}
9 Likes

The other thing I'd observe that's different is that if adding to each field is an operation that can panic, then assigning to self at the end prevents the possibility of the struct having an invalid state. This would probably only matter if you had a custom drop implementation.

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.