DEV Community

Cover image for The borrow checker in Rust
Bekka
Bekka

Posted on • Edited on

The borrow checker in Rust

Hey guys, Welcome to another blog post on Rust!

In the last post I mentioned the borrow checker briefly. In this post, I'm going to share what I've learned so far about the borrow checker. Now before we go into that, we need to go back to the foundational knowledge we had the last time.

Rust's uniqueness is memory safety, the way it achieves this is by implementing a mechanism of ownership.

What is ownership?

Ownership is a set of rules created to manage how rust manages memory. Languages like JavaScript uses garbage collection, this basically means it frees the memory when they are not used anymore. In Rust, this is managed by a set of rules that the compiler checks, if they are violated, the program won't compile.

These rules are as follows:

  • Each value that is contained in a variable is tagged it's owner, or simply put any variable initialised with a value is the owner of that value. It is tagged it's owner. For example:
let basket = String::from("Basket string");
Enter fullscreen mode Exit fullscreen mode

The variable basket here is tagged the owner here.

  • There can be only one owner at a time. This means that whatever value that is been allocated into the memory can only point to one owner at a time. For example: Using the example above but adding more modifications
let basket = String::from("Basket string");
let house = basket;
println!("This is a {}", basket);
Enter fullscreen mode Exit fullscreen mode

If you're coming from JavaScript like me, doing this won't bring any error when we call the first variable basket. In Rust, this will throw an error at compile time that;

we've moved the ownership to the new variable

Of course, this won't be the exact error, but that is what it means.
Therefore basket is no longer available.

  • When the owner goes out of scope the value will be dropped. This means that when we initialise a variable in a function(which is also a scope) or any scope, the value is dropped when the scope is over. For example,
{
let apple = "apple";
}

println!("This fruit is an {}", apple);
Enter fullscreen mode Exit fullscreen mode

This won't compile because the scope of apple has been dropped before we could access it.

What is the borrow checker?

This can be referred to as the mechanism in the compiler that checks and validates the ownership rules in your program. Whether it's a reference or if the variable owns the value.

We can't talk about the borrow checker without talking about references, the stack and the heap. For you to understand the borrow checker well, you need to learn how rust data types are stored. Because of the uniqueness of the language, you need to know whether a value is stored on the stack or the heap. It's crucial in Rust development.

The Stack and the Heap

Both the the stack and the heap are available to your code at runtime, but they are structured in different ways.

The stack stores the value in the order It gets them and removes the values in the opposite order. This can be referred to as the "the last in, first out" order. To explain this convention, think about a stack plates or a stack of books, you have to remove from the top to avoid destruction, 😆. Removing from the stack is called "popping" adding to it is called "pushing". All data stored on the stack must be a known fixed size.

The heap is less organised, when you put data on the heap, you request a certain amount of space. The memory allocator finds an empty slot in the heap,if the memory is big enough, it allocates it to your value and returns a pointer, which is the address of the location. To explain this better, think of a park. Let's say John and his friends/family decide to go out on a picnic, they need to take a few things or a lot of things for the picnic. John goes to look for a space at the park or rent a space. The space depends on the people, their things and so on, this space can be compared to allocating memory on the heap.
The exact location of the picnic can be compared to the pointer. Let's say the picnic is under a mango tree, to locate the picnic, John tells his friends, the picnic is under the mango tree, that's how his friends are able to locate him easily.
At the end of the picnic, they go to their various homes. The space for the picnic is no longer in use. This can be compared to when the value on the heap is now deallocated or cleaned up at the end of the program. The park can be compared to as the heap.

References:- A reference is like a pointer in that, It's an address we can follow to access data stored in that address that is owned by some other variable. A reference is guaranteed to point to a valid variable of a particular type, unlike a pointer. Let's go back to the picnic example, remember John's picnic was under the mango tree, which is a location. A pointer will still point to a location even when it doesn't have any value. References don't, that's why there's another concept of lifetimes. This will be another topic, I don't want to overload this post, 😄.

So that's the basic concept of "the borrow checker", the rules that guides it, the mechanism and my thought process.
I recommend reading through the Rust book. It's where I'm learning how to write Rust. See you soon!

Top comments (2)

Collapse
 
nuex001 profile image
Nuel

Nice article, can't believe it's a year plus🙌

Collapse
 
ayomide_bajo profile image
Bekka

thank you😁