2

I have a struct with a couple of operators implemented for it:

use std::ops;

/// Vector of 3 floats
#[derive(Debug, Copy, Clone)]
pub struct Vec3 {
    pub x: f32,
    pub y: f32,
    pub z: f32,
}

/// Add operator
impl ops::Add<&Vec3> for &Vec3 {
    type Output = Vec3;

    #[inline(always)]
    fn add(self, rhs: &Vec3) -> Self::Output {
        Vec3 {
            x: self.x + rhs.x,
            y: self.y + rhs.y,
            z: self.z + rhs.z,
        }
    }
}

/// Subtract operator
impl ops::Sub<&Vec3> for &Vec3 {
    type Output = Vec3;

    #[inline(always)]
    fn sub(self, rhs: &Vec3) -> Self::Output {
        Vec3 {
            x: self.x - rhs.x,
            y: self.y - rhs.y,
            z: self.z - rhs.z,
        }
    }
}

/// Scalar multiplication operator
impl ops::Mul<&Vec3> for f32 {
    type Output = Vec3;

    #[inline(always)]
    fn mul(self, rhs: &Vec3) -> Self::Output {
        Vec3 {
            x: self * rhs.x,
            y: self * rhs.y,
            z: self * rhs.z,
        }
    }
}

I want to use the operators:

let a = Vec3 { x: 0.0, y: 0.5, z: 1.0 };
let b = Vec3 { x: 1.0, y: 0.5, z: 0.0 };
let c = Vec3 { x: 1.0, y: 1.0, z: 0.0 };
let d = Vec3 { x: 0.0, y: 1.0, z: 1.0 };
let result = 2.0 * (a + b) - 3.0 * (c - d);

This code will not compile because the operators are implemented for &Vec3, not for Vec3. To fix the issue, the last line would have to look like this:

let result = &(2.0 * &(&a + &b)) - &(3.0 * &(&c - &d));

Which doesn't look that nice anymore.

I understand that I could implement the operators for Vec3 to avoid that problem, but what if I still want to use immutable references to these vectors on the stack? Is there perhaps a way to give Rust some hint that if I write a + b and there is no operator for Vec3 + Vec3, that it could try and look for a &Vec3 + &Vec3 operator instead, and if found, take the immutable references for both arguments automatically?

3
  • 1
    alternatively, you could have a,b,c,d as references to begin with. Commented May 26, 2021 at 12:30
  • 1
    Thanks, that's true. The intermediate results of the +/-/* operations would still be Vec3s, though, so the line would look like let result = &(2.0 * &(a_ref + b_ref)) - &(3.0 * &(c_ref - d_ref)); Commented May 26, 2021 at 12:44
  • 3
    It is common to implement binary operators for both references and owned values, e.g. for Vec3 + Vec3, &Vec3 + Vec3, Vec3 + &Vec3 and &Vec3 + &Vec3. This way, all intermediate results can be passed by value – it's fine to move them anyway. Together with making your variables references to begin with, this allows you to write the expression exactly in the form you want. Commented May 26, 2021 at 13:19

1 Answer 1

5

No, there is no way of automatically taking a reference when adding two values.

You could write your own macro that does this, I suppose. In usage, it would look like:

thing!{ a + b }
// expands to
(&a + &b)

I'd expect that this macro would quickly become tiresome to write.

See also:

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.