# Changing values through `Option<&mut T>` in a struct

I have some troubles with changing a value through a reference in a struct `B`, e.g.

I want my instances of the special (non-owning) struct `A` and `B` not to be mutable, because I am still under the impression I do not need to change the references `&mut` to point to some other stuff.
When I make `o` mutable I can use `Some(v) = &o.i[0].as_deref_mut()` where I can then change `v` (that is `i`),

``````struct A<'a> {
i: [&'a mut usize; 2]
}

struct B<'a> {
i: [Option<&'a mut usize>; 2]
}

fn main() {

{
let mut i = 3;
let mut j = 5;
let n = A {i: [&mut i, &mut j]};

*n.i[0] += 3; // `n` does not need to be mutable.
}

{
let mut i = 3;
let mut j = 5;
let o = B{i: [Some(&mut i), Some(&mut j)] };

if let Some(v) = &o.i[0] {
*v += 3; /// <<<<< FAILS: How to get to a type `&mut usize` but without making `o` `mut`.
}
}
}
``````

You might be confusing several different things here.

First, immutability is transitive. If you insert even a single immutable reference into a stack of mutable references, you won't be able to mutate the referent at the end. `x: &mut T` makes `*x` mutable. `x: &mut &mut T` makes `*x` and `**x` mutable. However, `x: &&mut T` makes `*x` immutable (through that reference).

Second, in your code, you are not trying to change what the pointer points to. You are trying to add 3 to a reference itself. That doesn't make sense, Rust pointer arithmetic doesn't work like this (it doesn't exist on references, only on raw pointers).

So all in all, one possibility to make this compile is:

``````        let mut o = B{i: [Some(&mut i), Some(&mut j)] };

if let Some(v) = &mut o.i[0] {
**v += 3;
}
``````

This still doesn't change what `*v` points to. For that, you'd need to have another value and a mutable reference to that value, and then assign that mutable reference to `*v` (and not `**v`).

Indeed, I come from a C++ background and wasn't sure if in Rust `& &mut T` is the same as `(T const *)*` `(T*) * const`.

But isn't this a bit unfortunate, to change `o.i[0]` I must make `o` mutable.
To change `n.i[0]` I dont need `n` to be mutable. Suddenly changing from `&mut T` to `Option<&mut T>` requires a sudden change in mutability everywhere. Hm.

That is not correct. This is not about `Option`-vs-non-option. It's about the extra layer of indirection you introduced in the second example. In the first snippet, there's no extra layer of reference, but in the second one, you explicitly requested it by taking the address.

No, it's not "unfortunate", it's the very point.

It’s still barely possible to avoid the `mut` marker on `o`.

``````    {
let mut i = 3;
let mut j = 5;
let o = B {
i: [Some(&mut i), Some(&mut j)],
};

if let Some(&mut ref mut v) = o.i[0] {
*v += 3;
}
}
``````

Yes… the `&mut ref mut v` pattern looks a bit ridiculous, but it works

The fact that this works also relies on the fact that array-indexing is compiler-implemented and doesn’t use the `IndexMut` trait, otherwise, the indexing operation would require mutable access to the array itself.

6 Likes

Note that the `mut`ability of bindings:

``````let mut o = B { /* ... */ };
``````

can be considered effectively a lint, as you can always just

``````let o = B { /* ... */ };
let mut o = o;
``````

The type of `o` is the same here. The `mut`ability of the binding doesn't change the type. You just can't take a `&mut` to the `o` without the binding being `mut`.

This is in contrast with `&'a T` and `&'a mut T` which are distinct and very different types. You can't go from `&` to `&mut`.

So it's unfortunate in that you have to get use to specifying a `mut` binding when you need one, but there's not a deep semantic difference here. You still aren't able to modify `*n.i[0]` through a `&A`, for instance.

The main difference between the examples is that you didn't have to jump through hoops to get a mutable place expression without the `Option` in the way.

TL;DR, what you can or can't do with an immutably bound yet owned `let x = X` is not an indication of what you can or can't do with a `&X`.

3 Likes

`&` can be shared and is trivially copyable, while `&mut` by design is a guarantee of exclusivity. If `&&mut` didn't downgrade the inner reference to be shared like `&&`, then you could break the aliasing rules.

It's better to think of `&mut` == "mutex" rather than "mutable".

1 Like

That was exactl what I was looking for. I searched for away of matching the `Option` s inner `&mut` but without making `o` mutable. At this point I am wondering what is `&mut ref mut`?
Is it `&mut &mut` but circumventing the following

``````let temp: &mut &mut usize = o.i[0].as_deref_mut()
``````

which needs `o` to be mutable (hm...)

I think of `&` in Rust as refcounted pointers with lifetime, where the compiler assures the invariants:

• Only one write to the same storage or
• Multiple reads to the same storage.

Should'nt be too wrong off of what it is, right?

Update: I missed to say compile-time ref-counted.

With two important differences:

• They are compile-time refcounted, at runtime they're just pointers (or pointer+length, or pointer+vtable);
• They can't stop the value they point to from destruction and therefore must all expire by the time owner does out of scope.
3 Likes

It's a pattern that will re-borrow the reference instead of trying to move it. The `&mut` part dereferences and the `ref mut` part captures by mutable reference. It's less weird looking in more normal patterns such as `match (… as &mut Option<T>) { &mut Some(ref mut x) => …… }`. In fact, such patterns used to be so common that at one point a rule was introduced to the language that you simply write `Some(x)` instead of `&mut Some(ref mut x)` or `&Some(ref x)`, the former would previously have complained about trying to match a reference against a pattern for `Option` (essentially a type error).

1 Like

For other users: This goes deeply into reborrowing (vs. moving) which
as a start one might look here:

I have a hard time actually getting a grasp on it.

Basically it seems that reborrowing is the "reference-inspect" operation the compiler can introduce at some points contrary to a `move` of a `&mut` which will pass ownership (there can only be one (active) &mut). Reborrowing does not move the reference to another scope, but it creates another `&mut` with another referencial scope by looking at the original one where it points at, and the original `&mut` is set "on hold" (you can not use it until the new reborrowed `&mut` goes out of scope and the original becomes active again.

To understand the `&mut` part of patterns, see this article. I believe that's enough to understand that in

``````if let Some(&mut v) = o.i[0] {
``````

the `v` corresponds to the place of the `i: i32`. Then `ref mut` takes a `&mut` to that place instead.

Default binding modes (aka "match ergonomics") makes pattern behavior contextual based on the type in a "usually what you want" but more-complicated-to-reason-about fashion.`[warn(clippy::pattern_type_mismatch)]` can point out when those are kicking in, if you use `clippy`.

2 Likes

Nice articel! Should be directly added to the rust book.