Why does Arc::get_mut check weak references?

Hi everyone!

I was wondering why Arcs get_mut method also checks for weak references to avoid giving mutable access to the underlying data to more than one place.
Weak references cannot be dereferenced without converting them to an Arc first which begs the question why not allow the user to create Weak references and still use the get_mut method.
In my case that would be greatly beneficial :slight_smile:

Really curious about the actual reason for it and looking forward to reading your replies!

Because a weak reference can be upgraded to a strong one.

let v = Arc::new(1);
let weak = v.clone().downgrade();
let mutable_reference = Arc::get_mut(&mut v).unwrap();
let upgraded = weak.upgrade().unwrap();
let aliasing_shared_reference = &*upgraded;
2 Likes

Yeah true. Can’t believe that I overlooked something as trivial as this. Thanks!

I'm no expert, so I don't know if it's truly possible. But to do this a new operation is needed - something that temporarily takes the whole strong Arc. The Arc'ed value appears like it has no strong count anymore but still weakly referenced, so you temporarily take the value out of the Arc and can later put it back. The downside is that other weak pointers will observe the Arc as dead and later to be live again, which I'm not sure if it's allowed either (but this is similar to the Weak that you get in new_cyclic).

At least something with the same signature as fn get_mut(this: &mut Arc<T>) -> Option<&mut T> won't be able to do "temporarily take the value out of the Arc and can later put it back", since the returned Option<&mut T> does nothing when dropped, so there's no place to put the "later put it back" code.

On the other hand, with a different signature (e.g. returning a kind of guard object, or accepting a callback), this approach should probably be possible, AFAICT.

With the `get_mut` signature, in theory, a reasonable approach might be to just completely dissociate all remaining `Weak` references with the `Arc`, so there's no "later put it back"-kind of cleanup action necessary. I believe however that the current implementation of `Arc` cannot support such an operation of "dissociating" existing `Weak`s with the `Arc`, and it seems hard to pull off in principle, too, since newly created functioning `Weak`s would be able to coexist with the dissociated old ones. I suppose maybe something like a kind of "generation counter" for the `Weak`s might be necessary (where only the ones with the latest generation aren't dissociated), but this would increase the size of the `Weak` pointer itself.