3

So, I was writing some code and apparently R.A. didn't warn me about some erroneous stuff I had written in regards to how ownership works with lambdas.
So, a friend helped me rewrite some of my code, and this is just a play example, but their new code boils down to this:

let vec = Rc::new(RwLock::new( Vec::new() ));
let vec_rc = vec.clone();
let my_lambda = || -> () {
  vec_rc.write().unwrap().push(/* ... */);
}

But what I don't understand is how this works if vec_rc isn't mut.
From my prior knowledge, mutable in Rust cascades; in other words, if the "master-containing" object is immutable the rest will have to be too.

Could I please get some clarity as to what goes on under the hood?
Or is their code erroneous too?

KattyTheEnby
  • 87
  • 1
  • 7

1 Answers1

3

From my prior knowledge, mutable in Rust cascades; in other words, if the "master-containing" object is immutable the rest will have to be too.

This is almost always true... Until we consider interior mutability.

Interior mutability is exactly about that: changing a value through a shared reference. Moreover, while there are other shared references to it. The basic interior mutability primitive is UnsafeCell, but there are multiple abstractions built on top of it - one of them is RwLock (you can see it secretly contains an UnsafeCell).

As a side note, Rc<RwLock<T>> is almost always wrong: Rc is non thread safe, which defeats the whole purpose of RwLock. If you just need shared mutable stated over one thread, use Rc<RefCell<T>>. It is much more performant and can't block (so no deadlock debugging, just a simple panic if something went wrong).

Chayim Friedman
  • 47,971
  • 5
  • 48
  • 77
  • Thanks! I was unaware there was such a concept. – KattyTheEnby Jun 28 '22 at 10:55
  • Slightly unrelated, but: Is there a way to make custom types with interior mutability (without `RefCell`)? – KattyTheEnby Jun 28 '22 at 11:06
  • @KattyT.enbycat. Sure, just include one of the existing types in them. If you need really bare metal you can use `UnsafeCell`, but it requires `unsafe` and I really don't recommend it until you'll be proficient with Rust. – Chayim Friedman Jun 28 '22 at 11:08
  • I *just* edited my question because I realized it wasn't clear. - But if there isn't a way, it'd be interesting to know how `UnsafeCell` itself pulls this off. It seems like a normal `struct` to me. – KattyTheEnby Jun 28 '22 at 11:09
  • @KattyT.enbycat. Ah, I understand. `UnsafeCell` is a magic: the compiler knows it ([it is marked `#[lang = "unsafe_cell"]`](https://doc.rust-lang.org/1.61.0/src/core/cell.rs.html#1837), `lang` means a special type known to the compiler) and treats it specifically. You cannot emulate that for your structs. – Chayim Friedman Jun 28 '22 at 11:14
  • I see. - I was thinking there was some magic. Alright. Thanks for the help. – KattyTheEnby Jun 28 '22 at 11:23