# Why does move occur in simple math `+`?

Here's a generic function that makes a vector of sums. It works when I write `T: Copy, U: Copy`, but does not this way, because it can't move val1, val2 from behind a shared reference.

So, question 1: do I understand this right: when you do even a simple math calculation, you must either borrow & copy, or move the value? (question 2: And for numeric types `copy` happens silently under the hood?)

``````use std::ops::Add;

fn add<T, U>(v1: Vec<T>, v2: Vec<U>) -> Vec<T>
{
let sum_func = |x: (&T, &U)| -> T {
let (val1, val2) = x;
(*val1.clone()) + T::from(*val2.clone())
};
v1.iter().zip(v2.iter()).map(sum_func).collect::<Vec<T>>()
}

fn main() {
let vec1:Vec<i32> = vec![1, 2, 5, 5, 12, 20];
let vec2:Vec<f64> = vec![1.5, 2.5, 5.5, 5.5, 12.5, 20.5];

}
``````

question 3: I see `Copy` trait implements `Clone`. For numeric calculations, is it ok performance-wise to just clone `val1/val2`, or it's better to require `Copy`?

``````    where   T: Clone + From<U> + Add<T> + Add<Output = T>,
U: Clone
...
val1.clone() + T::from(val2.clone())
...
``````

It depends on the `Add` implementations available. It's technically possible (but discouraged in case of non-trivial values) to have an implementation which goes from `&T + &U` to `V` directly.

Essentially, yes - implementations for binary operations on references to primitive numbers delegates to the implementation for the numbers themselves by dereferencing.

If the value is `Copy`, it's guaranteed that it can be `memcpy`d without problems. In that case, `Clone` is expected (not obliged, but expected) to behave exactly like `Copy`.
If the value isn't `Copy`, then cloning it can have arbitrary effects like memory allocation.

So, it's up to you whether you can tolerate these effects in your code or not. But for `Copy` types, there should be no difference (and the exceptions are probably some degenerate cases).

1 Like

Yes, you can't move an object out of a shared reference, because that would mean taking ownership of it and rust only has a single owner for all data.

For all types implementing copy it will be used when moved out of a shared reference or when passing as a value to a function.

I think `Clone::clone()` is generally slower than copying you data. But I'm not 100% sure.

Bonus tipp:
You already own the vectors in the add function. Then you can simply use

``````v1.into_iter().zip(v2.into_iter()).map(sum_func).collect()
``````
1 Like

Thanks.

Oh, that's a mistake in my example. The vectors should be borrowed and not destroyed in the process.

No. For Copy types, any sensible implementation of Clone also only performs a bitwise copy.

2 Likes

Can you explain why this is discouraged?

Maybe this has been mentioned in or is related to: Surprising: &1 + &1 == 2

But I don't remember.

Simply because it's highly surprising when the arithmetic operation incurs, e.g., some hidden `.clone()`.

1 Like

Wouldn't it be better to have an impl for `&T + &U -> V` that allocates, than to require ownership and thus require cloning an input whose storage cannot necessarily be reused? Or am I misunderstanding the alternative proposed?

1 Like

The best way in many cases probably is to do as it is done with `String`, i.e. to have `T + &U -> V` - in this case, you can reuse the allocation from the left side, but not force the user to give up ownership of the right side.

3 Likes

If you're going to do that, it's probably best to implement `AddAssign` and then dispatch to it in a generic `Add` implementation, so that they always stay in sync:

(untested)

``````impl<U> Add<U> for MyType where Self: AddAssign<U> {
type Output=Self;
fn add(mut self, rhs:U)->Self { self += rhs; self }
}
``````
2 Likes

You can only reuse the allocation from the left side in some cases (if there is enough spare space). So `a.clone() + &b` may do two allocations, whereas `&a + &b` would only do one allocation. So `&a + &b` is better.

It's best to have all 4 versions.

2 Likes