Can this be simplified? (this seems awfully repetitive)

#1

I ahve this code:

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

impl Add<&Vec2F32> for &Vec2F32 {
    type Output = Vec2F32;
    fn add (self, rhs: &Vec2F32) -> Vec2F32 {
        Vec2F32 {
            x: self.x + rhs.x,
            y: self.y + rhs.y,
        }
    }
}

impl Add<Vec2F32> for &Vec2F32 {
    type Output = Vec2F32;
    fn add (self, rhs: Vec2F32) -> Vec2F32 { self + &rhs }
}

impl Add<&Vec2F32> for Vec2F32 {
    type Output = Vec2F32;
    fn add (self, rhs: &Vec2F32) -> Vec2F32 { &self + rhs }
}

impl Add<Vec2F32> for Vec2F32 {
    type Output = Vec2F32;
    fn add (self, rhs: Vec2F32) -> Vec2F32 { self + &rhs }
}

Then, I need to add impls for Add, Sub, Mul, Div. This fees awfully repetitive to have four (each combo of struct vs ref).

Is there a way to reduce the repetition?

#2

I don’t see the need for any of the owned variants, you’re just taking a reference, doing the addition, and discard it anyways. Let the caller just pass a reference, so you just need 1 Variant here. Unless I’m missing something … :slight_smile:

#3

You can use macros. The standard library and the num crate do it that way.

2 Likes
#4

The problem is that if we only have the ref variants, we have to write:

&(&a + &b) + &c

since (a + b) is going to return a struct, not a ref.

#5

Ah yeah, that’s a bit of a papercut. To bad operator’s aren’t like methods in this regard. Still, depending on what code you’ll write maybe that’s a worthwhile tradeoff.

#6

You could just make the Vec2F32 Copy and not bother with the reference versions.

2 Likes
#7

On a 64bit system, a ref is 64bits, so it’s the same size as two f32’s right? So there’s no additional memory cost, and might have better memory locality.

#8

Yes, I would also reccomend using clippy, as it catches these sorts of things, clippy is pretty nice.

1 Like