Check out a free preview of the full Rust for TypeScript Developers course

The "Value, Mutable, Immutable" Lesson is part of the full, Rust for TypeScript Developers course featured in this preview video. Here's what you'd learn in this lesson:

ThePrimeagen explains the difference between values, references, and mutability. Values can be accessed by their owner or through a reference. By default, references are read-only (immutable). To mutate a value through a reference, the reference must be defined using &mut.

Preview
Close

Transcript from the "Value, Mutable, Immutable" Lesson

[00:00:00]
>> I did wanna say a little something about value, mutable reference, mutable borrow, immutable reference, immutable borrow. These are things that JS devs don't think about. So I just want to give just a small one. So when you hear me say the word value, you know what I mean?

[00:00:16]
If you hear me say the word immutable borrow or immutable reference, or really when I just say reference, I mean this, or if you hear me say mutable reference, they have meaning. And so I'm just gonna jump over here. And we're gonna create a new one of these, and I'll zoom it in.

[00:00:32]
And so when I do something like x=5, this thing right here, this is a value, right? That is something that is sitting there. It's in memory. It is the thing. The owner of said value is x. Now in Rust land, you can refer to a value. So I can do something like y= a reference to x.

[00:00:57]
That means y refers to x. Whatever value x is, if you were to print out y, it'd be the same thing. This is a read-only reference. It means I can only look at the data. This is very, very important. If I were to do something like this, mutable reference to x, it means not only can I look at the data, I myself am allowed to change the data.

[00:01:21]
This is very important distinction. This is not really done in any other language where you have references that are either read-only or read-and-write-only. This is what gives Rust a lot of its power and safety, is this distinction right here. And so for you to be able to do this, your original variable also has to be mutable.

[00:01:38]
You have to declare that what I am gonna mutate, it may be able to be mutated by reference. And so you'll see probably once or twice today some sort of function on implementation that looks like function do_this. By the way, Rust loves underscores. It complains that you if you don't use snake case, one of the worst decisions ever created.

[00:01:59]
But now I love snake case, and now I hate camel case. Camel case, the worst decision ever created. And so you will see this often where you'll see something like either reference self, oopsies, there's an l in self. And this just simply means it's a function that refers to self.

[00:02:14]
It is not self. It does not contain the value, but it contains a reference to the value. This will become more clear, as I say this, you'll also see something that looks like mute self. This means that this function takes in, you can only call this function on an object that is defined as mutable.

[00:02:33]
This is very important kinda distinction. And so that way you kinda separate out functions that mutate versus functions that don't mutate. So you know that old array.reverse problem? If you didn't define it as mutable, you wouldn't be able to call array.reverse in Rust. Because it would say, sorry, this thing mutates, you have to let me know that I can mutate it.

[00:02:52]
So it adds a unique flavor of security or safety that just isn't present. All right, so there you go. That's just a little brief one. I just wanna make sure that you understand. So reference means read-only. Mutable reference means write and read reference. And value means the thing itself.

[00:03:09]
>> So if y was defined as a mutable reference to x, what circumstances would we wanna send y instead of just sending x?
>> So that kinda gets into something called the borrow checker.
>> Okay.
>> So in Rust, I'll just kinda give you a quick one so you can hear these rules.

[00:03:26]
In Rust, when you program, there can be only one value owner, only one Lord of the Ring, if you will. You can have as many as you want read-only references, if there's no write-and-read references out. You can only have one write reference and no read references. So there's a few rules to how you can use a variable.

[00:03:47]
And by having these rules, there's this chart that exists somewhere. I saw it on some YouTube video and it was really, really clever. I can't remember what it was or else I'd definitely give you a shout out right now. But there's this notion that there exists a set of all safe programs.

[00:04:03]
But you could never write a compiler to be able to detect every form of safety. So by limiting what you allow, you have a subset. And the subset is guaranteed to be safe, but it can't detect all safeties. Just like that whole array, where you have some contents and then I say, foo[2], I can't really tell you that's safe or not safe.

[00:04:27]
I don't know at compile time, it would only be known at run time. And so that's why you have this idea of safe, unsafe, what is allowed. We'll go over it, but I just wanted to make sure you understand value, reference, mutable reference. Or the more technical term, immutable borrow, mutable borrow.

[00:04:45]
You'll see that term a lot in the compiler errors. All right, one more thing the unit you saw me kind of reference this once or twice. The thing about Rust is that everything is an expression, which means you can actually omit return statements if you don't have a semicolon.

[00:05:00]
I personally hate that, you'll never see me not have a return statement. I like the word return. I like to use my semicolons, it's just who I am. So this right here, this if true, actually returns a value. I could do, let foo, if true, print this. The value is literally nothing.

[00:05:17]
It's that there is nothing. So it's called the unit. This is also why I believe you can't, they didn't have closures like that cuz an empty argument closure would look just like a unit. How do you parse that out as a compiler, or you technically could never parse that out, it'd be an ambiguous tree, it would explode?

[00:05:33]
And so you'll see me often do something like this, where inside of a function say, this won't make any sense right now. But I'll have something that looks like this as my return value. This says, hey, this thing could be an error. And at the bottom of my function, you'll see me do something like this.

[00:05:50]
It means I'm returning the unit of nothing. It doesn't exist, but, hey, we're okay. Everything went okay in this function, but we used the nothing unit, just to let you know. Because there's no value. Cuz sometimes you have functions that have side effects, but they don't actually do anything for you, or return anything.

[00:06:05]
So just so you know, if you see this, that's a unit. It's the nothing. It's not like undefined cuz you can't put methods on it, you can't do some things like that.

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