Using ops with heap objects

Hi everyone,

I've been playing around a bit with rust, and reading the code of nd-array. I'm trying to implement some forward auto-differentiation library and I am now stuck on a design question: What would be a good way to use std::ops traits with objects that allocates.

To illustrate my case, let's say we are implementing a very simple library to manipulate vectors of f64 and some element-wise operation, say addition. We also want our library to handle "views" that is not only vectors that can own their data, but vectors that can be backed by a &[f64], maybe because we want to extract parts of a vector, or maybe because we can receive some read only vectors from a C FFI (my case). My current implementation is something like:

use std::ops;
use std::borrow::*;

struct AlgVector<T : Borrow<[f64]>>(T);

impl<T> AlgVector<T>
where
    T: Borrow<[f64]>
{
    pub fn to_owning(&self) -> AlgVector<Vec<f64>> {
        AlgVector(self.0.borrow().to_owned())
    }

    pub fn view<'a>(&'a self) -> AlgVector<&'a [f64]> {
        AlgVector(self.0.borrow())
    }
}

impl<L, R> ops::Add<AlgVector<R>> for AlgVector<L>
where
    L: BorrowMut<[f64]>,
    R: Borrow<[f64]>,
{
    type Output = Self;
    fn add(mut self, rhs: AlgVector<R>) -> Self {
        self.0.borrow_mut().iter_mut().zip(rhs.0.borrow()).for_each(|(selfx,rhsx)| *selfx += rhsx);
        self
    }
}

which I like because it is quite generic, small, and doesn't hide allocations, but it forces the user to write things like x.to_owning() + y.view() which aren't so readable.

ndarray's approach is much easier to use but there are so many levels of nested types that it seems a bit much to implement and understand, and the error messages become quite complex.

So my question is: have you ever faced the same issue ? How would you have an implementation for ops that doesn't allocate every time while still being nice to use ? Would it even be possible to have something that is optimal in its allocations and doesn't require the user to manage them ?

Thanks for reading

Take a look at the biginteger crates. They allow you to use references to objects with the operators.

Hi, thanks for your answer. Unfortunately; all approaches I have tried with references still end-up having some clunk in the way. Notably, the num_bigint doesn't have this notion of "view", but if you add it, the possible combinations with reference/not reference becomes quite large and I have always ended up hitting type issue.

If you can make your type essentially be a Cow, then you could make it seamless. The operation could return the same type, so there would be no need for users to call to owned, or anything similar.

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.