[solved] A function with two mutable references that can be the same as parameters

Hello!

In a project, I have this kind of function..

fn do_something<T>(foo: &T, bar: &mut T) {
    // ...
}

..but I want to be able to call this function with a reference to the same value in a and b, so I ended up writing an other function :

fn do_something_<T>(foo: &mut T) {
    //...
} 

Is there any naming convention for this kind of situation? do_something_ isn't a nice name and I wonder what to choose. (For info, the function is sigmoid and it takes two references over a f32 : the input and the output)

Maybe it isn't possible, but it would be nice if we could do something like that :

fn do_something<#a, T>(foo: &T + #a, bar: &mut T + #a) {
    //...
}

To indicate the compiler that it is safe to pass two mutable references over the same data!

Rust only allows a single mutable reference to a data location at a time - you can't have any other references to it at the same time, including immutable ones. I don't fully understand why you want to do this though.

Also, why can't the function take an f32 and return an f32?

Indeed, that's why I have to write two functions for my problem!
Actually I want to pass references over a structure that wraps a pointer over a GPU-allocated vector, so I prefer to not allocate a vector in the function^^ Sorry I thought it wasn't important to mention it
Do you have any idea on a meaninful name for both functions I had to write? (Something generic that I can apply to other functions like tanh, relu...)

Ah, so you have a more complex struct here, not just f32.

So you’re saying sometimes foo and bar point at different structs and sometimes you want them to point to the same one?

Can you split the vector inside and pass the segments? This would be similar to split_at_mut() in std. Does your function actually attempt aliasing operations on the data? In other words, is the vector accessed mutably and immutably into the same locations within it? Or are the accesses disjoint?

So I’m not sure what a good name would be, but perhaps you can rethink the API based on the questions above.

Mmm I can take slices of a vector, but I dont see how it is supposed to help me,
The first function does something like bar[i] = sigmoid(foo[i]) for every i,
while the second does foo[i] = sigmoid(foo[i])
The second function does exactly the same thing as the first one in the case where both references reference the same data

I run into this same problem in crypto: one function variant has separate immutable input and mutable output slices while the second variant has a single mutable in_out slice where the input value is overwritten by the encrypted/decrypted output value.

I believe that @ltei is asking for a nomenclature recommendation, which is also my interest. What is considered a best practice (more or less) within the Rust community for naming two functions that are related in this way?

This is not a Rust community convention, but personally I would make the first variant the "canonical" one (since it seems to be a better default choice and to be usable in a broader range of contexts) and add an "_inplace" suffix to the second method's name.

3 Likes

@HadrienG Thanks. That name is how even the literature categorizes the second approach. For example, the primary use of the overwriting version of encrypt/decrypt is often to „protect data in place", such as transforming a memory page before transfer to/from a backing store, or to keep it opaque in memory between uses.

Thanks! That is indeed a good choice I can apply to every function of this kind