Add `with mut` syntax to mutate variable in place


#1

IMHO as Rust we sometimes need to mutate variable it will be nice to have syntax like this:

let vec = Vec::new();

with mut vec {
    vec.push(1);
    vec.push(2);
}

println!("{:?}", vec);

It will be the same as:

let vec = Vec::new();

let mut vec = vec;
vec.push(1);
vec.push(2);
let vec = vec;

println!("{:?}", vec);

This syntax will allow to visually mark code that will mutate variable.


#2

What about

let vec = {
    let mut vec = Vec::new();
    vec.push(1);
    vec.push(2);
    vec
};

#3

This involves adding a new keyword, which I am against (unless its already reserved?), and +1 to @stebalien’s comment, thats a much better and more orthogonal way to do it. We dont need to add functionality that mirrors something else at the moment.


#4

Is there a good place to put this technique in the documentation? Or a place where techniques and good practices like this can be gathered in general?


#5

Note that the current syntax is very close to what you are proposing:

let vec = Vec::new();
{
    let mut vec = vec;
    vec.push(1);
    vec.push(2);
}
println!("{}", vec);

This does not scale very well for many mutable variables, see the var macro for that.


#6

You’re moving the vec into a scope and dropping it, though.


#7

Ugh. It’d be nice to cut down on macros such as var!. It makes no real sense and confuses people (e.g. myself).


#8

You are right, my code does not work because println uses a dropped vec. Sorry about that, I should have tested it before posting.

I don’t think it can be fixed, but it should be possible to write a macro, something like

with_mut! vec {
    vec.push(1);
    vec.push(2);
}

(Not sure whether this syntax is possible with the current macro rules though.)

I would really like to write let mut (a, b, c) instead of let (mut a, mut b, mut c).


#9

This works:

macro_rules! with_mut {
    ($($v:ident),+ in $e:expr) => {
        let ($($v,)+) = {
            let ($(mut $v,)+) = ($($v,)+);
            $e;
            ($($v,)+)
        }
    }
}

fn main() {
    let a = 0;
    let b = 0;
    with_mut!(a, b in {
        a = 1;
        b = 2;
    });
    println!("{}, {}", a, b);
}

#10

Why? The gain in number of symbols is small and the loss in readability for people not intimately familiar with your code is huge. Additionally, imagine that you have a bug in your macros (perhaps, someone accidentally writes let mut (a, mut b, c)) - how easy would it be to debug your code?