Thought: OpAssign operators on non-lvalues


#1

The limitation of assignment operators to lvalues brings with it an unfortunate edge case:

playground

use ::std::ops::AddAssign;
struct Vectorize<'a>(&'a mut [f64]);

impl<'a> AddAssign<f64> for Vectorize<'a> {
    fn add_assign(&mut self, x: f64) {
        for elem in &mut *self.0 {
            *elem += x;
        }
    }
}

let mut v = vec![1.0, 2.0, 3.0];
    
// error[E0067]: invalid left-hand side expression
Vectorize(&mut v) += 1.0;

assert_eq!(v, vec![2.0, 3.0, 4.0]);

The workarounds are…

…uh, interesting.

{ // workaround by giving it a name
    let mut it = Vectorize(&mut v);
    it += 1.0;
}
    
// these might earn you a couple of raised eyebrows...
*(&mut Vectorize(&mut v)) += 1.0; // workaround via DerefMut
[Vectorize(&mut v)][0] += 1.0; // workaround via IndexMut

What’s the reasoning behind this limitation?


#2

FWIW, it also works to call Vectorize(&mut v).add_assign(1.0).


#3

I think this issue, if the experiment goes well, will let you do that.