Ownership and Borrow question

Im new to Rust and struggling a bit to understand ownership and borrow syntax used.
I have a simple struct

#[derive(Debug)]
struct Foo {
    a: u32,
    b: String,
}

Following is allowed

let u = &mut Foo { //works
        a: 1,
        b: "hello".to_string(),
    };
    u.a = 2;

It means: u MUTABLY BORROWS Foo but CANNOT be reassigned to a new &mut.

So, why does the following does not work

let v = mut Foo { //fails with "expected expression, found keyword `mut`"
        a: 1,
        b: "hello".to_string(),
    };
    v.a = 2;

Shouldnt' this also mean v mutably owns Foo? Why is this disallowed?

I know following is allowed

let mut s = Foo { //works
        a: 1,
        b: "hello".to_string(),
    };
    s.a = 2;

It means: s MUTABLY OWNS Foo and hence s.a = 2 is allowed.

Why is the placement of mut important in above two scenarios?

I'd recommend reading: References and Borrowing - The Rust Programming Language

let u = &mut Foo

means u cannot be reassigned to anything.

let v = mut Foo

Is just the wrong syntax. If you want Foo to be mutable, then you do

let mut s = Foo

I'm a bit confused about the question. Placement of keywords is important in any language. mut Foo is the wrong syntax. What do you want mut Foo to do?

1 Like

I may be misunderstanding but I think in the first example it's truer to say that u immutably borrows a reference to Foo but the Foo being referenced is itself mutable.

I think let v = mut Foo wouldn't make sense because you create an immutable v but then tell it Foo is mutable. Isn't that a contradiction?

To be clearer, the difference is there's two things involved in the first example (a reference and Foo) whereas there's only one thing in the second example (Foo) which you first say is immutable (let v =) and then say is mutable (mut Foo).

At least that's my impression.

1 Like

Just like &mut Foo mutably BORROWS Foo mut Foo should mutably OWN Foo. I understand a language comes with its syntax but to be consistent shouldn't they both be on one side of =?

You may think of this in the following way: after

let x = &mut Foo { ... }

x is immutably owning the mutable borrow. This mut chatacterises the borrow itself, it is some internal property of the borrow, not connected to its binding to variable.

Rust does NOT have a concept of mutable value. If you own that value, you can do whatever you want on them. mut variables just there to provide simple lint, while & and &mut are deeply integrated to language guarantee so you can't borrow some value while its &mut exist somewhere.

6 Likes

I may be misunderstanding but I think in the first example it’s truer to say that u immutably borrows a reference to Foo but the Foo being referenced is itself mutable.

Got that part.

I think let v = mut Foo wouldn’t make sense because you create an immutable v but then tell it Foo is mutable. Isn’t that a contradiction?

Not it's not. That's what let v = &mut Foo does but instead of owing Foo V has borrowed Foo.

That makes sense. So when it comes to owning or borrowing a REFERENCE only we need to use & or &mut on right side of =.

&mut Foo part is clear to me. I was mainly confused between let mut s = Foo and let s = mut Foo.

let s = mut Foo just doesn't exist. There's no such thing.

mut is a re-assignment lint for variables (including function arguments), and can't be applied to expressions or values.

The mut keyword has a different meaning when qualifying the mutability of a reference and the mutability of a binding.

When the mut keyword appears to the left of the = sign, it qualifies the mutability of the binding. The binding is not the value itself, it is a way of accessing the value.
A mutable binding allows to reassign the value it is bound to, modify it and take a mutable borrow to that value. It says nothing about the mutability of the underlying value. As others noted, this meaning is primarily intended to allow the developer to express their intent of mutating a variable through a binding, so that the compiler can emit messages when the actual code diverge from the expressed intent (e.g., when you mutate a variable through a binding that was not denoted as mutable, or when you don't mutate a variable through a binding that was denoted as mutable). Note that this lint is useful in practice, and caught numerous bugs for me in the past while developing (such as instantiating a mut binding and forgetting to mutate it before returning its value).

When the mut keyword appears to the right of the = sign (and of the & sign), it qualifies the mutability of the reference.
A mutable reference allows to reassign the referenced value, modify it, and (mutably or immutably) reborrow it. It also guarantees that the value will not mutate through any other reference of through the owner while the mutable reference is alive (and in the absence of interior mutability). As others also noted, this meaning is integral to the "ownership system" of rust and cannot really be removed.

Your proposition of having mut qualify a value would be a third meaning to that keyword. And I can see a world where it would make sense! But in the timeline we are in, rust doesn't have immutable values. As such, it wouldn't make sense to mark a value as mut, because all of them are! It is not useful to express "immutably owns" and "mutably owns", because everyone always "mutably owns", so we just say "owns".
In particular, this means that even if you pass an owned value to a function through an immutable binding, the function will be able to modify the owned value it now owns, simply by rebinding the value to a new, mutable binding:

fn mutate_owned(owned /* immutable binding */: String) -> String {
    let mut owned = owned; // rebind the value with a mutable binding
    owned += &" mutated"; // OK on a mutable binding
    return owned
}

This is not really surprising: after all, the function now owns the value, it is logical that it could do anything with it, including modifying it.

Similarly, I sometimes use the ability to shadow existing bindings in rust to express "areas where a variable will be mutated", using mutable and immutable bindings:

let x = String::from("some string"); // x won't be mutated right away
if not validate_string(&x) {
    return WrongFormatError; // Note: could use ? operator here to be more idiomatic
}
let mut x = x; // serious business now, we will mutate x
encode_string(&mut x);
// ... some other logic
let x = x; // all operations from now on won't modify x, except if it is rebound again.
// ... some other logic
println!({}, x);

Note that you don't have to rebind all bindings immutably as soon as you are done mutating them or mutably just for the short time where you want to mutate them, it might be OK to have a single mutable binding in the code above. But the ability to rebind variables can come in handy in certain scenarios.

5 Likes

@AlwaysLearning, you may want to read my posts about this: Mutation - part 2: To mut or not to mut · Another one bytes the Rust!

Note that it is not exactly beginner friendly (there is the official Rust book for that), the posts are all about asking "existential" programming questions, related to Rust's mut keyword meaning (in other words, it is a very expanded version of the difference explicited by @zrk)

1 Like

@zrk
A lot of people have used the word "binding". Coming from Java world "binding" means which method to call at compile/run time. What exactly does it mean in Rust? Is it same as assignment?

Is let s = Foo{} considered binding without mut?

Im a little confused by the second statement

A mutable binding allows to reassign the value it is bound to, modify it and take a mutable borrow to that value. It says nothing about the mutability of the underlying value.

So something like

let mut s = Foo {a: 2, b:4}

means I can do
s.a = 10
So doesnt it mean I CAN modify the underlying value?

Nice. I think this is what I need to clear my confusion. I will read when I have enough time.
Thanks.

A binding is terminology that is, I believe, borrowed from the ML family of languages.
Here is what Real World OCaml has to say about it:

At its simplest, a variable is an identifier whose meaning is bound to a particular value. In OCaml these bindings are often introduced using the let keyword. [...] Every variable binding has a scope , which is the portion of the code that can refer to that binding.

So a binding is a named way to refer to a specific value, valid for a specific scope. When writing let a = 42;, we would say that a is bound to the value 42, and we could say that a is an (immutable) binding to 42. Other languages may prefer to use the term variable for such a thing.
I prefer to use the binding/value terminology when speaking about the various properties of either the binding or the value (as is the case in this thread), I personally find it clearer than variable that blurries the line between the value and the binding.
If you did some python, I believe it uses a similar terminology, where an assignment binds a name to a value, and the value is typed, but the binding is not. This is why it is legal to assign a value of a different type to the same binding in python:

x = A()
x = B() # legal

Your understanding is correct, that was poor wording on my part. Of course, you need a mutable value to be able to mutably bind it, so having a mutable binding tells us that the bound value is mutable. I guess, what I meant to highlight is rather the opposite case: you can have an immutable binding to a value, and have that value still be mutable.

@Yandros: Nice looking article, might give it a read too :slight_smile:.

1 Like

I would say all values in rust are mutable. After all, all temporaries are mutable.

It's only bindings that can be immutable, preventing you from actually mutating the value.

3 Likes

IMHO, this term might be even more older, it possibly comes from lambda calculus or term rewriting system in general, and let is nothing but a syntactic sugar. For example:

let x = 10;
...something using x

means

(\x -> something using x) 10

IMHO, actually it's rather reverse, binding should always immutable and a

let mut x =10;
x = 100;

means there is some "hidden" reference r bound to x, and r may point to different values. But this does not change the fact that the binding of r to x is immutable. At least, that is the case for ML languages.

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.