The Add
trait is defined as seen in the documentation.
When implementing it for a Vector, it was required to copy it into the add method to allow syntax like v1 + v2
. If the add
implementation is changed to support borrowed references and thus prevent a copy, one has to write &v1 + &v2
which is undesirable.
What is the preferred or best performing way of doing this ?
(In C++, self would be a const Vector<T>&
, as well as rhs
, but still allow the desired v1 + v2
semantics.)
The Code
For completeness, an excerpt of the code I am using right now
use std::num::Float;
use std::ops::Add;
#[derive(Debug, PartialEq, Eq, Copy)]
pub struct Vector<T: Float> {
x: T,
y: T,
z: T,
}
impl<T: Float> Add for Vector<T> {
type Output = Vector<T>;
// Probably it will be optimized to not actually copy self and rhs for each call !
#[inline(always)]
fn add(self, rhs: Vector<T>) -> Vector<T> {
Vector { x: self.x + rhs.x,
y: self.y + rhs.y,
z: self.z + rhs.z }
}
}
#[cfg(test)]
#[test]
fn basics() {
let v32 = Vector { x: 5.0f32, y: 4.0f32, z: 0.0f32 };
let v32_2 = v32 + v32;
assert_eq!(v32_2.x, v32.x + v32.x);
assert_eq!(v32_2.y, v32.y + v32.y);
assert_eq!(v32_2.z, v32.z + v32.z);
}
Since your
Vector
only contains three values implementingFloat
trait (which means that they are eitherf64
orf32
) you shouldn't really bother that they are copied unless you have profiled your program and determined that multiple copies cause performance drop.If your type was not copyable and required allocations on construction (like big integers and big floats, for example), you could implement all possible combinations of by-value and by-reference invocations:
and reuse the allocated storage in implementations which accept at least one argument by value. In that case, however, you will need to use
&
operator if you don't want to move your values into the call. Rust prefers explicit over implicit; if you need reference semantics, you have to write it explicitly.FWIW, you can take a look at this program and especially its assembly output. This piece of assembly, I believe, is responsible for all arithmetic operations:
Looks neat to me - the compiler has inlined all operations very nicely.