I wouldn’t know about a place where it’s documented explicitly, but generally if you have a function receiving and returning an owned argument, you can assume it operates by modifying the argument if it’s decently implemented; if the modification doesn’t do something like a resize, etc. and the types involved aren’t representing immutable data, the modification should generally happen in-place.
In the case of ndarray, the situation is also highlighted in the types because they contain generic arguments specifying the kind of ownership/representation you have:
impl<'a, A, B, S, S2, D, E> Add<&'a ArrayBase<S2, E>> for ArrayBase<S, D>
where
A: Clone + Add<B, Output = A>,
B: Clone,
S: DataOwned<Elem = A> + DataMut,
S2: Data<Elem = B>,
D: Dimension + DimMax<E>,
E: Dimension,
{
type Output = ArrayBase<S, <D as DimMax<E>>::Output>;
fn add(self, rhs: &ArrayBase<S2, E>) -> Self::Output { … }
}
impl<'a, A, B, S, S2, D, E> Add<&'a ArrayBase<S2, E>> for &'a ArrayBase<S, D>
where
A: Clone + Add<B, Output = A>,
B: Clone,
S: Data<Elem = A>,
S2: Data<Elem = B>,
D: Dimension + DimMax<E>,
E: Dimension,
{
type Output = Array<A, <D as DimMax<E>>::Output>;
fn add(self, rhs: &'a ArrayBase<S2, E>) -> Self::Output { … }
}
impl<A, B, S, S2, D, E> Add<ArrayBase<S2, E>> for ArrayBase<S, D>
where
A: Clone + Add<B, Output = A>,
B: Clone,
S: DataOwned<Elem = A> + DataMut,
S2: Data<Elem = B>,
D: Dimension + DimMax<E>,
E: Dimension,
{
type Output = ArrayBase<S, <D as DimMax<E>>::Output>;
fn add(self, rhs: ArrayBase<S2, E>) -> Self::Output { … }
}
impl<'a, A, B, S, S2, D, E> Add<ArrayBase<S2, E>> for &'a ArrayBase<S, D>
where
A: Clone + Add<B, Output = B>,
B: Clone,
S: Data<Elem = A>,
S2: DataOwned<Elem = B> + DataMut,
D: Dimension,
E: Dimension + DimMax<D>,
{
type Output = ArrayBase<S2, <E as DimMax<D>>::Output>;
fn add(self, rhs: ArrayBase<S2, E>) -> Self::Output { … }
}
Looking at Output
types, you see that Add<&'a ArrayBase<S2, E>> for ArrayBase<S, D>
and Add<ArrayBase<S2, E>> for ArrayBase<S, D>
output ArrayBase<S, <D as DimMax<E>>::Output>
, so this will be modifying the first argument (if possible), and Add<ArrayBase<S2, E>> for &'a ArrayBase<S, D>
outputs ArrayBase<S2, <E as DimMax<D>>::Output>
(note the S2
!), so it’s modifying the second argument in-place (if possible); Add<&'a ArrayBase<S2, E>> for &'a ArrayBase<S, D>
outputs Array<A, <D as DimMax<E>>::Output>;
, which is always a newly created owned array, it doesn’t use the S
or S2
argument. I don’t quite understand the nuances of broadcasting in ndarray, so I can’t tell you what happens if the shapes don’t agree.