The Rust Programming Language Mutable References
Transcript from the "Mutable References" Lesson
>> So here I have a mutable vector. So a vector by 30 twos, so in this case, just 9090 9095 and here I have a mutable reference to a vector. So this ampersand Mutt is basically saying I want to get back a reference to a Vec and I want to be able to mutate that Vec.
[00:00:19] So normally references are sort of look but don't touch there they're immutable references which means you can borrow this thing you need to give it back to me in exactly the same condition that you found it. Mutable references kind of stretch the metaphor a little bit because basically saying like, well, I'm gonna lend this thing to you, and you can give it back to me, but it's okay if it's different.
[00:00:38] So maybe the metaphor might be, I'm going to lend you something where once you use it, it's going to be changed in some way. And when you give it back, I understand that it's gonna be a little bit different than how I gave it to you. Whereas the traditional immutable bar is like I expect to be getting back exactly what I gave you.
[00:00:55] An example of a function where this comes up is the clear method. So clear is a method that says I wanna take a vec and I wanna just empty it out. I want to throw away all the elements that were inside of it. Now clear does not take ownership of this vec.
[00:01:08] It says once you call it like, yeah, it's a problem. I've emptied it out, but you still own it. No big deal. You can still use mutable years after calling clear on it. Because it's a reference. It's just saying, I want to give this method a reference to my mute my years vec.
[00:01:25] And it's gonna give it back to me afterwards. It's not, I'm not transferring over deallocated I'm gonna give us sort of an elevated level of not only can you look at this thing, changes to it, you're free to mutate it. What's the difference? And this is exactly the type that you'll find in the definition of clear it says fn clear and then it says &mut self so instead of and set self.and then inside there, set self length to zero.
[00:01:55] So you can contrast this with a function like length, which only takes a immutable reference to self. So when you're reading rust documentation, you'll encounter both of these things like you'll see some Methods like Len which takes ampersand self and you'll encounter things like clear which takes ampersand.
[00:02:13] But self whether or not you want them it's kind of similar to lead versus lead but knowing that something can't mutate it is potentially beneficial. Of note though, there is one important difference between Mutable references and immutable references that does not come up with let and let mut.
[00:02:31] So, let's say that I wanted to add additional call, let's say I had all three of these pc's laser codes right here. So, I had years which is [INAUDIBLE] then I had mutable years which is mutable reference to this Then right after that I said I wanna call them mutable years dot Len.
[00:02:47] Well, believe it or not, that would not compile because mutable references have additional restrictions that immutable references do not have. So let's say that I wrote this right here. So I said yours is vec of 1999 in 2005 then I said, let yours ref one is a normal reference to this like we've seen in the previous section.
[00:03:07] And then I said years ref two is an old reference, no problem. That's all well and good. You can have as many immutable references to something as you want at the same time. But with mutable references, that's not true. The rules are a little bit different with mutable references you can only have one mutable reference at a time.
[00:03:26] And furthermore, if you have one mutable reference for the active that is to say still in scope, you're not allowed to have any immutable references at the same time. So if you try to do this, you'll get an error saying I can't borrow this as mutable because it's not declared as mutable.
[00:03:41] So in order to do ampersand mud on yours, yours has to be defined using let mud. Okay, so let's say I fix that great. Now I can define my years to no problem. But if I try to do years three with another mutable reference to the same thing, I'll get an error saying can I borrow yours as mutable more than once at a time.
[00:03:59] So it says here's the first mutable borrow. And then here's the second mutable bar. So again, in the same scope, we cannot have these these sort of active at the same time. First one of them needs to go out of scope and no longer be accessible, and then the second one is allowed to happen.
[00:04:12] We'll talk about why in a second. And then similarly if you have an immutable borrow, you can't have any mutable borrows this is not gonna work says cannot borrow yours as mutable because it is also borrowed as immutable. So here's the immutable borrow ampersand yours and here's the mutable borrow.
[00:04:28] So we're getting a healthy dose of borrow checker errors right here. These are the types of things you can encounter in the wild. When you're starting out with rust. And also doesn't help if you switch them around, it's not, it's no help if you do the mutable one first and then the immutable one.
[00:04:42] Again, cannot borrow is immutable because it is also borrowed as mutable. So really, it's very strict about this, you can only have one mutable reference active at a time. And then any number of, or you can have any number of immutable ones, but they're mutually exclusive. It's either one mutable.
[00:04:57] Or any number of immutable, but you can't mix and match. The reason for this is concurrency. So there's a whole category of bugs that we're not going to get into here called data races. And these can happen in like C and c++ all the time where basically you have multiple threads running in parallel and they have some shared memory, and one of the threads writes to that piece of shared memory.
[00:05:19] At the same time is another thread is trying to read from it. And potentially what can happen is that there's a race condition and one of these things gets partway through reading the value in memory while the other one starts writing in the middle of it. And you can get a totally great Garbled value much like us after free and and double free data races are extremely painful and difficult to reproduce and then debug.
[00:05:43] So they're they're really really nasty stuff and the way that rust prevents them at compile time by by ruling them out with its compiler Is exactly the system where mutable references. You can only have one of them active at a time, which basically means no matter how many threads you've got going, the compiler will enforce that only one thread can possibly have write access to something.
[00:06:02] And if it's writing, nobody else is allowed to read it at the same time, or for that matter to write to it. So this is how rust prevents data races. We're not gonna get into rust concurrency in this course, but I do wanna just take a second and note this If you're wondering, why this restriction exist and why you see this burrow checker errors?
[00:06:17] It' for concurrency, it's a way of preventing data raises from happening. So, one of reasons claims to fame, in comparison to see a c plus plus in particular, is that it has really high performance concurrency. But it is able to roll out, like to guarantee no data raises.
[00:06:32] And this is how. So we won't spend any more time talking about concurrency though just so you know why those restrictions are there.