Check out a free preview of the full Polyglot Programming: TypeScript, Go, & Rust course

The "Values, References & Mutation" Lesson is part of the full, Polyglot Programming: TypeScript, Go, & Rust course featured in this preview video. Here's what you'd learn in this lesson:

ThePrimeagen discusses the three types of Rust values, values, references, and mutable references. Values can have only one owner, many references can exist with the constraint that there are no mutable references alive, and one mutable reference and no reference can exist simultaneously.


Transcript from the "Values, References & Mutation" Lesson

>> So let's jump down here. There's three types that you gotta think about at least overall which is a value. So what is a value? This is the value, right? That is the vector, that is the thing itself. Second, there are references, I can create a reference to this value, which means that you can read data from that value.

And third, I can create a mutable reference to that value, meaning that it is a reference to a thing in which I can also mutate. And so unlike JavaScript, you cannot mutate a vector unless if you say, hey, this thing is mutable. And I think that's a very important difference between the two because it allows a much more kinda strict paradigm.

You won't get things off getting mutated somewhere else and then being surprised about it. It also allows for some other cool things. So obviously I already went over this, you can only have one value. Now there is a small exception to the rule, which just like in C++ when we assigned, it copied, you can also implement the copy trait on your type.

So if you create a struct, you implement the copy trait. When you assign, you'll actually get it to implicitly copy which could or which could be great or bad. And so numbers as you can imagine, they just copy, that makes perfect sense, it makes no sense if you could only have a number that you cannot copy.

So fairly easy, doesn't matter, we can do that. Two, references, you can have as many references as you would like. Everything can be a reference. So as you can see here, x equals five, y is a reference to it. There we go. So let's just do that really quickly so we can kinda see how that looks cuz I feel like it's always better to program.

So x equals that, y equals a reference to x. And then we can go x plus y. Now if we look at x, it is a type of an integer that is 32 bits long. For those that don't know what 32 is, that's how many bits are in a number, approximately 4 billion is the highest number you can represent with 32 bits.

And y is a reference to a 32. Which also means that I cannot do things like this, I cannot go y equals six. And why not? Well, you can't do that. You cannot mutate this thing cuz it is not a mutable reference, right? You cannot change it. But I can certainly use its value.

So x plus y is the same thing as doing x times two, whatever you wanna call it because this is okay, you can have that out. But what you cannot do is have a reference to something and a mutable reference to something at the exact same time. This is a very important part about rust.

And this is actually where it guarantees a lot of its safety is because you cannot have things that can read at the same time where things can write to cuz that is gonna cause some fundamental problems. We've all seen this, and JavaScript doesn't quite have this because JavaScript doesn't quite have threads.

But you've seen problems where you're expecting one vote, we call them data races. I think still in JavaScript, it's kinda funny, but you have race conditions still in JavaScript. And that is a lot of it comes down to this. You're waiting for something to change. And you shouldn't be passing all these things and things just become convoluted and very, very hard.

Cuz everyone's kinda pointing at each other, hoping someone's gonna do it whereas with rust, you just can't really do that as easily. I'm sure there's a way with unsafe mode where you could cause some similar problems but we're just not gonna touch unsafe mode and unsafe mode is still fairly safe in comparison, but with this, you cannot do that.

So if I just had this, this is totally fine. Now I can go z equals seven, right? I can do some fun things here, right? Or I gotta dereference this. There we go. And so now I can do this which, what do you think the answer is gonna be?

Cannot do these fun things, right? What are we gonna get here? My goodness, can I borrow x's mutable? Can't forget all these things, can't obviously borrow a mutable version of x if x is not mutable itself, right? So you're gonna get a lot of complaints from the compiler.

It's gonna tell you a lot of things, that small simple changes just did just inundated you with like, here's this is wrong. Hey, that's wrong. Hey, this is wrong. Look that's wrong. And, of course, when you print it out, you can see that it's seven. It's just something to always remember.

So in the C++ land, which is not important JavaScript, you can do things like this. This gives you obviously, scope control. Because what it's saying here is that z is going to live, but it lives up until this point. Now this is not technically true. There's actually a better explanation of how things live in rust in the book Rust for Rustaceans.

But for our sake, just think of it at the end of every scope is how long something lives for. So how rust guarantees safety is that rust can go as an agony like this, right? Why does this work? How come this works when I have two things that I'm manipulating, right?

I have a mutable and immutable here. Well, x is not manipulated inside of here and it only has a single reference x or z to x that's mutable. And then we do something with it and then we drop z. Z no longer lives, therefore x can be remutable again and so now, boom, we're doing it right here.

And so that's kind of how rust works is that it kinda lives on these lifetime edges and you can just use swirlies as your general kinda cut off point for where do you think these things happen. Like I said, there is actually a much more detailed version of it.

It's just irrelevant for our case and you only run into it very rarely. But there you go. So now we have that beautiful little thing right there. Just obviously can't do that. Not gonna work. All right, so do we have any questions? It's kinda stopped here. We can kinda go over some more examples if you need to, cuz It's important just to have a basic understanding that you have a value.

The value only exists in one spot. When you assign it to somewhere else, it literally moves that value into the new one. You cannot reference it to the old one. So just like I did before with the vectors, well, where was it? Where were you? Right, right here.

You cannot reference a anymore. A has been moved, I cannot push right here, right? If I try to push, what is it gonna do? A's already been moved, right? And so in rust world, everything gets moved as you assign it so if I hand a value to a function, do I have the value anymore?

No, the function has the value. If the function doesn't return me the value, then that value is gone. So if it's a vector filled with a bunch of items, and you don't get it back, it's gone forever. So you can hand in references to it. So that way, you still retain the value but they have a reference to it to read it.

If they need to mutate it, you can hand it a mutable reference. They can mutate it, then the lifetime of that mutable reference is done, and then you can do and go on your merry way and do the things you need to do with it. So long as you keep those things in your head, I really don't think rust is that hard.

That's like the hardest part and then you go into async world and then you cry and async and everything's terrible. So we won't go there like I said but I just wanna say that one more time any questions feel free.
>> So just to clarify, if you declare a variable as mutable and then you borrow it using the ampersand, it becomes immutable at that point and then you can't reference it again as mutable.

>> So let's do that again. Okay, so you're saying, hey, I have a, it's mutable, right? I'm gonna give it a type just so it quits complaining. This will be a vec of i32, right? So that's what it's complaining about saying, hey, I don't know what I am because I haven't given it a type yet.

And so if I hand it to B, and this is fine, this is perfectly fine, these are just warning saying, hey, it's an unused variable. It put a underscore so don't worry about that. So yes, I can have a reference out to this thing that is mutable, that is fine.

But what I cannot do is I cannot have a mutable reference along with a reference out. Once you start going into this land, you start getting into the very dangerous land of, hey, you're not allowed to do these things. It's gonna start causing a bunch of problems because if I start passing things around, you start getting into the borrow checker, losing its mind saying, hey, stop doing that, you're not allowed to do that.

But that's pretty much it. So long as you keep things, just think of it as steps and be a little bit more precise as you walk through when you want things to mutate when you don't want things to mutate. Most people always talk about you should never have mute unless if you really need it as a keyword.

It's a rare word you need. All right, we got a question.
>> What if you actually have two owners, I'm thinking about double linked lists, etc.?
>> So you cannot simply. One does not simply create a double linked list in Russ that is because there's this whole thing, what is it called?

It's called too many lists. I believe it's what it's called learning rust with too many link lists, there we go. This is actually gonna go over a lot, this is like what I consider one of the best places to learn rust from. The sad part about this really awesome content here is that it's geared towards very new people to rust, which convoluted its explanations with like, hey, this is what a reference is.

When I was hoping it'd be like the more kinda like you already know what references are, references just point to something, right? But this is a very, very good thing to kind of understand linkless. So only one thing can ever own a value. And so often what people do is they create reference counters are an RCA reference count.

That's a way you can pass out multiple reference to this. You can guard it with what is called a mutex. So that way multiple people can edit it. There's a bunch of there's interior mutability. There's all these confusing things eventually that go on for allowing better maintaining this but it just takes a bit more time to do things.

Whereas with, Go or TypeScript, you just don't ever think about it. Just everybody has access to everything and everyone can change it. And that's just the way it is. And so rust is just gonna make you go a little bit slower and think about a few things. So, nice try though on the doubly linked lists.

Okay, you're not gonna catch me on that one. Well, let me just program one up really quickly for you in that way.
>> Here.
>> I guess I'm not understanding what's the difference between a reference and a mutable reference.
>> A mmutable reference allows you to mutate the underlying item.

Whereas a reference only allows you to read the data. So they make a distinction there. You can only have one mutable reference out, cuz two things cannot both read and write data at the same time. And they just put it some of these concrete rules in so that way it's easier for you.

It's really easier for the compiler to tell you you're wrong.
>> Kinda weird question here, so like, how it's happening is kinda seems it's well if you have a value for a, it's pointing to memory in the soil into therapy to actually move the value there but does a still point to that location and memory and there's nothing there?

>> So I mean, I can't speak to the exact specifics of what a is actually pointing to at that point. But the compiler will simply not let you run that program. So it's because it's a valueless item and they can pre-compute that it's a valueless item there for this program is doing something wrong, right?

It's effectively like a use after free air in C++ and so it's just like this thing is a dangling pointer now, you may never ever use this this construct again. But one cool thing about rust, just to throw this out here so if B equals A there, there is this thing called shadowing which I really, really like, is you can read declare variables, right?

So a is a vector of i32, l can now make a into a string but I have to use the keyword let, which is really convenient especially in like loops or things where you want to go, I need to change the type from one to another. This is kind of more annoying and something like go pick is go does not allow this.

And so you have to come up like, okay, I have a config, I have a thing that has a config and you start getting this config or whatever, the word problem becomes new, like, I just need to change from one type to another, and then it just is very painful.

Whereas if I try to reassign a, I'm not gonna let me obviously the whole, you can't assign an immutable variable twice. It's just not allowed, right? It's gonna try to catch everything you're doing all the time. It's very good at doing it too. It's gonna make you feel bad and frustrated.

And so don't feel upset if you're frustrated, just long as you can keep that one thing in mind, you have a value it points to something. Whenever you pass the value, it has gone from you. You no longer have it. There's only one owner, there's only one owner of the ring, right?

And whoever has it is, the Lord, say, of the ring, perhaps all the rings if there's references out we can keep going with this. I don't think we should though. You'd be surprised to know that I made that up on the spot. All right, let's keep on going.

Learn Straight from the Experts Who Shape the Modern Web

  • In-depth Courses
  • Industry Leading Experts
  • Learning Paths
  • Live Interactive Workshops
Get Unlimited Access Now