If I want to call .next() on an iterator, I need to have a mutable reference to the iterator:
let input = "myteststring";
let mut chars = input.chars();
But now chars can be reassigned to something else, which isn't what I wanted. Is there a way to resolve this? I don't understand why mutable references have been conflated with reassignment.
Imagine we have some special keyword mut_ref_only which only allows to take mutable reference(unique reference) but not allows direct reassignment into it.
let mut_ref_only i = 42;
*(&mut i) = 0;
But you can still reassign to the variable with only taking &mut of it.
I don't understand where &mut comes into it (amongst other things, like understanding how &mut actually works). Would you be able to relate this back to my original example?
Is there a reason why the theoretical mut_ref_only couldn't work? Why wouldn't the compiler be able to enforce this?
You can think of mut as being contagious. If I want to mutate something deep within an object then every object above it needs to be mutable. So in self.some.vec.push(42), not only does the vec field need to be mutable, but so does self and some.
But how do we introduce that initial mutability? In Rust it is done by making the variable at the very top mut or being given something behind an &mut reference (where the caller would have had to make their variable mut).
The reason it wouldn't work is because mut_ref_only is logically unsound.
Say we changed the language's semantics so there is some marker to say "you can't reassign this variable, but you are still allowed to mutate it" (i.e. mut_ref_only).
What I can do is take a mutable reference to that variable (which is valid) then copy a new value into that place using the dereference operator.
// Let's say we have two variables
let a: u32 = 42;
// This one can't be reassigned, but you can take a &mut reference to it
let mut_ref_only b: u32 = 0;
// Make that reference
let some_reference_to_b: &mut u32 = &mut b;
// then overwrite the old value for "b" with "a"
*some_reference_to_b = a;
// That was just a verbose way of writing
b = a;
So just by allowing me to take an &mut reference to some variable I've been able to reassign that variable to something else. But hang on, mut_ref_only was meant to explicitly prevent this!
That contradiction means our hypothetical "you can only take a &mut reference to a variable and can't reassign it" rule is logically inconsistent, hence why it can't work.
struct Thing(String);
impl Thing {
fn do_specific_stuff(&mut self) {
}
}
fn replaces_using_mutual_reference(thing: &mut Thing) {
let _ = std::mem::replace(thing, Thing("bar".to_string()));
}
fn main() {
// I want to do the specific stuff, but I want to avoid reassignment
// like `thing = other_thing;`
let mut thing = Thing("foo".to_string());
thing.do_specific_stuff();
// But if I can `do_specific_stuff`, I can do anything else that uses
// a mutual reference to myself...
replaces_using_mutual_reference(&mut thing);
// Oops, I've basically been reassigned
println!("{}", thing.0);
}
Well that's kind of my point. Why doesn't it prevent it? What's stopping the compiler from enforcing that?
I suppose I'm actually more interested in the corollary. Is there a way to allow reassignment without the need for the variable to hold a mutable reference to the data? If not, why wouldn't such a thing be feasible?
Yes, I think I haven't made myself clear at all. I'm new at this and don't have all of the necessary language to ask all of the right questions. I do know enough to know that your "foo".to_string() example is not at all what I'm asking for though.
The best example I can think of to explain my point is how const works in Javascript. All const does is guarantee that the value cannot be reassigned. The internal mutability of the value being assigned is not relevant. If the value is supposed to be an immutable data structure, it's the sole responsibility of that data structure to use const itself.
So what I'm wondering is kind of the inverse of what const does. I'm trying to keep track of a value in a variable, and I don't want to mutate the value at all and do not care if it is mutable or immutable. I do want to reassign the value of this variable, and refer to it in various places so that they all have the "latest" value I'm tracking.
Right now, the only way to achieve this is to declare that a variable with mut, which also requires that the value it holds is mutable, which (as @Michael-F-Bryan mentioned) is contagious in that it requires everything all the way down to be mutable. But I don't care about those values being mutable and have zero intention of ever attempting to mutate them, I just want to reassign the value in a variable.
No, it doesn't require anything. In Rust, values ans types don't have mutability; bindings ("variables") do. If let xyz = expression; compiles, then let mut xyz = expression; is also guaranteed to compile; you don't have to have all references be mutable in the right-hand side.
That sounds like you want to reference the same value from multiple places at the same time, but still be able to change it without invalidating the other references. That's exactly what internal mutability enables, so it is relevant . However, it also typically has a cost -- you need to make sure no one is reading your structure while it is being written to -- so Rust makes you explicitly opt-in to the functionality by wrapping your type in the appropriate locking (or otherwise mutable-access checking) data structures.
For example, you might end up with an Arc<Mutex<YourType>> . There are other possibilities with various trade-offs, to serve different needs. (Threaded or multi-threaded, capabilities of the type, need to obtain references or just copies of entire types, etc.)
It's been said before, but that is logically unsound. In other words, there isn't anything that any compiler or there, now or in the future, can do about it.
No. In fact at this point it should be obvious that changing some value in e.g. a struct (using a &mut binding) and changing the value of the struct itself (using a mut binding) are in a fundamental sense the same operation. The real difference is only in how much data is altered: only a field in the former, and all fields (and the container value itself) in the latter.
I'd argue that that is simply the latter case in my paragraph above, only applied to values that are immutable borrows. So nothing fundamentally special there, and thus of course it counts.
In a sense this could be managed with something like
let mut v: Rc<T> = p.clone();
or even with something like
let mut v = &data;
Either would allow you to reassign v to a new value, but not to modify the value that is pointed to. Of course, they also prevent anyone else from modifying it.
For references, you can independently specify whether the reference can be reassigned, and whether the referred-to value can be modified.
Here, x can be reassigned, but *x cannot be modified:
let a = 5;
let b = 6;
let mut x = &a;
x = &b; // reassigning is OK
// *x = 7; // compile error: modification is not OK
Here, x cannot be reassigned, but *x can be modified:
let mut a = 5;
let mut b = 6;
let x = &mut a;
// x = &mut b; // compile error: reassigning is not OK
*x = 7; // modification is OK
The difference with Javascript is that in Javascript variables always store references, while in Rust you don't need the extra indirection. In your original code there are no references, so there is only one level of mutability.