2

In rust, you can upgrade an immutable variable:

let v = Vec::new(); // Immutable
let mut v = v;      // Mutable
v.push("hi");       // Succeeds

Or downgrade a mutable variable:

let mut v = Vec::new();   // Mutable
let v = v;                // Immutable
v.push("hi");             // Won't compile

My question is - why?

From what I understand, the underlying memory in use to store values of variables is never immutable. Every memory address can technically be written to. Immutability is an artificial constraint, that someone sets on us (like the kernel), or we set on ourselves.

When I say:

let v = vec!["a", "b", "c"];

I'm saying that I want a variable in memory with these values, and I don't want it changed by any code later on. If I try to change this variable at some point, give me an error. This is me defining the constraint.

If you can later just do:

let mut v = v;

making it mutable, and change it, this seems to defeat the entire purpose of immutable variables. At that point, you might as well just make all variables mutable (like in Python), because immutability is not guaranteed. Not only is it not guaranteed, but a programmer can get a false sense of the guarantee of immutability, and make mistakes based on this assumption.

At least with constants, there's a guarantee of immutability. The purpose of a regular immutable variable is unclear if you can just make it mutable at any point.

John
  • 2,551
  • 3
  • 30
  • 55
  • 6
    You aren't "upgrading" you are moving an old value into a new mutable value with the same name. – PiRocks Feb 04 '21 at 02:19
  • 1
    It is important to note that you can only "upgrade" immutable values to mutable when you own them. You cannot, for instance, upgrade an immutable _reference_ to a mutable one. If you own a value, you are free to do with it as you please -- you can move it into a (im)mutable binding at any point if you like. Admittedly, this makes immutable bindings not nearly as important as immutable references. If you want to specify that a value is permanently mutable, use a constant. – EvilTak Feb 04 '21 at 02:50

2 Answers2

5

In rust, you can upgrade an immutable variable:

let v = Vec::new(); // Immutable
let mut v = v;      // Mutable
v.push("hi");       // Succeeds

This isn't upgrading a variable. You are creating a variable v and moving it into another variable also called v. The original v is no longer accessible. In debug mode the generated code likely has two completely different (stack) memory addresses for the first and second v.

As for downgrading the same applies.

this seems to defeat the entire purpose of immutable variables.

Once you have moved a value you can no longer use it, and you cannot move a value if there are references to that value in existence. Therefore you never have a situation where you have a mutable reference to something that is now immutable.

pretzelhammer
  • 13,874
  • 15
  • 47
  • 98
PiRocks
  • 1,708
  • 2
  • 18
  • 29
  • I thought that's what happens, but I wasn't sure. Thanks for confirming. That seems like a distinction without a difference however. Apparently, `"Downgrading" a mutable binding to immutable is quite common in Rust` -- https://stackoverflow.com/a/54595440/6423456. Almost seems like something the compiler should watch for, and prevent, just like it does with tons of other cases that are technically possible, but shouldn't be done (like ownership). Not having mutable references to an immutable variable isn't the problem. The programmer not knowing why a supposedly immutable variable changed is. – John Feb 04 '21 at 14:59
-1

Rust allows for redefinition of variables. So in your example you declare a new variable v and copy the vector into it :

let v = Vec::new(); // Immutable
let mut v = v;      // New Mutable <—-
v.push("hi");       // Succeeds

Because the vector implements the copy trait.

You can make your sample (not) work as you intended by borrowing as reference:

let v = Vec::new(); // Immutable
let &mut v = v;      // Doesnt compile
v.push("hi");
  • 3
    Vectors do not implement `Copy`. The vector is being moved into a new variable binding instead. Also, you probably meant `let v = &mut v;` in the second code snippet. – EvilTak Feb 04 '21 at 02:35
  • 2
    The second snippet doesn't compile because it's invalid syntax. – Aplet123 Feb 04 '21 at 11:33