While programming in Rust, we stumble across many rules that, at first, are really unfamiliar to begin with.
However, there's a certain rule that, while programming, I face the most: Multiple Mutable References.
It usually happens when you try to pass a variable into a function as a reader, and then pass that same variable as a writer. C or C++ will happily compile and let you run the code, but Rust throws a massive red error in your face!!!.
In order to understand why this happens, we have to look at how C programmers dealt with it.
Pointers
Back in the old days, programming in C was like having everything at your disposal. A pointer was just an address in memory, nothing else. If you wanted to have ten different pointers all pointing at the same byte of RAM (Aliasing) and you wanted three of them for example to simultaneously try to edit that byte (Mutation), the C compiler would say, "Whatever you say, Boss".
But this absolute freedom of memory management created LOTS of bugs that kept devs awake for days!!!
Imagine processing bank transactions: Two Threads (workers), Alice and Bob are running at the exact same time:
- Alice is reading your account balance in order to deposit $70
- Bob is reading your account balance because you just bought a $30 game
Because C places almost no restrictions on aliasing and mutation, multiple parts of a program can read from and write to the same memory simultaneously. As a result, both workers read your balance and see $100.
- Alice says: "Alright: $100 + $70 = $170". And then Alice prepares to write $170
- Bob says: "$100 - $30 = $70". And then Bob prepares to write $70
They both put their new numbers into the database. So whichever one writes a millisecond slower OVERWRITES the other. It can make your $70 profit vanish into the void (This is called Data Race)
The Single-Thread
Even if you don't use multi threading. C would still shoot you at your own feet. Imagine like you are reading a list of names, right?. Then you have a pointer looking at the first name (Aliasing). But further down your code, you accidentally tell the program to add a hundred thousand new names to that list (Mutation).
The computer realizes the current memory array is too small to hold a hundred thousand new names, so what it does it silently pick up the entire list, moves it into a bigger space in RAM, and DELETES the old one. But your original reading pointer doesn't know that the program did that!!!!. So then It tries to read the next name and reads literal deleted garbage, causing the program to instantly crash. This behavior is called Iterator Invalidation.
Solution
For decades, language researchers studied these crashes and behaviors. And eventually they realized something profound:
- Aliasing by itself is literally harmless: Like if you have a million threads reading a list simultaneously. If nobody changes throughout that time, then nothing breaks.
- Mutation by itself is also harmless: If only Bob is allowed in the room to edit the bank account, then the math is always perfect. The crashes only happened when Aliasing and Mutation were combined.
The XOR Gate
When Graydon Hoare started building Rust, one of his goals was to eliminate an entire class of memory safety bugs before a program could even run. Rust achieves this by enforcing a fundamental principle at compile time, commonly summarized as Aliasing XOR Mutation.
Just like the XOR logic gate many of us encounter in our first digital logic course, a piece of data can have aliases (multiple shared references) or it can be mutated (through one exclusive mutable reference), but never both at the same time.
If you didn't get it at first, I'll give you an analogy from a professor that I had at university:
"You can have your wife in the house, or your lover when she's not inside, but not at the same time or it'll be a disaster".
That's essentially what Rust enforces. You can have many readers, or one writer—but never both at the same time.
-
Option A (Aliasing): You can have unlimited read-only references (
&name). But the moment you create one, the compiler locks the data and no one is allowed to mutate it until everyone is done READING. -
Option B (Mutation): You can have exactly one mutable reference (
&mut name). But in order to get it, you must be THE ONLY POINTER int he room!!.
Top comments (0)