The Real Reason to Use Rust
In the process of fixing one problem, the Rust community discovered so much more.
Oh boy. Here it comes. Another developer that soy’d out after drinking the Kool-Aid is here to proselytize us about their weird crab language.
I hear you. Like anything peaking on the hype cycle, there’s a lot of unwarranted focus and claims floating around with a core of validity underneath. Let’s look past the noise and see what’s really behind this growing phenomenon.
Why Rust Exists
Rust was created at Mozilla to solve a major problem with systems programming, memory safety. They need a solution to write safe low level code at scale. Manual memory management is fast, but perilous. It’s extremely trivial to leak memory, crash, or worst of all introduce a security vulnerability. When you’re writing code in an unsafe language, the stakes are high. Every single line of code must be interrogated, because misplacing a single pointer operation is all it takes to generate headlines.
You will eventually mess up. Even if you’re perfect, and you’re not, the person next to you isn’t. The 3rd party library you call into isn’t. By convention that should be a borrowed pointer returned, but how do you know it doesn’t leak? Static analysis tools aren’t a valid retort. That’s just the rust borrow checker with extra steps 🥒.
Any one protesting this is either unfamiliar with the space, or a deeply unserious person.
What’s Rust’s True Strength? Why is it so Loved?
However, I think that’s missing the point. Yes, the borrow checker is a big deal. But this does nothing to explain why year after year Rust wins in surveys as most loved and most admired. Let’s be real, how many people want to do low level programming? How many actually care that the language increases security at scale? Sure, abstractly we all want the world to be more secure, but that’s not translating into a cultural phenomena.
Rust’s claim to fame is that it offers the speed of C1 without giving up abstraction or ergonomics. It’s a blazingly fast, no garbage collection language that can be used as low level as for writing drivers or as high level as a web front end.
It’s worth emphasizing this point. Rust’s unique offer is that you can have the performance and “run anywhere” aspects of low level programming without giving anything up from higher level languages.
Some may object here by saying Rust gives up a lot in terms of learning curve and iteration speed. My counter is that my claim is narrowly that you get low-level without giving things up. Much of the learning curve and slower iteration speed has nothing to do with the low vs high level compromise. Rust has a very different philosophy than other languages. It doubles down on the idea the underpins static typing: finding and fixing bugs pre-check in and pre-deployment is vastly cheaper. You can disagree with that assessment, or rightly point out that in the early stages of a product we generally care more about velocity than quality, but this is an orthogonal topic of discussion on a different aspect of Rust.
Rust is loved because it offers:
- High level ergonomics without losing speed or compiler friendliness.
- Best in class developer tooling.
- An algebraic type system for expressive code and making errors unrepresentable.
- A top down emphasis on correctness. If your code compiles and has basic test coverage, it’s going to work in prod.
My Introduction
I was first introduced to Rust at Microsoft where we used it to rewrite various Host Node services in Azure. I was vaguely aware of the language before, but didn’t care much. Seemed cool for browsers, but in my area as long as you wrote modern C++ things were fine. Over time though I came to appreciate how bad the state of C++ is. Yeah on paper you can write good code. I’ve had only 1 memory leak my entire career, and that was from calling into a poorly documented internal library improperly. But most people touching these code bases don’t actually understand C++ well, it’s mixed with C in truly risky ways, and at scale communication failures will happen like in the case of my 1 leak.
Thus, I was glad we were switching to it but otherwise didn’t think much. This all changed after using Rust for a few months. I felt like I had the wool torn off my eyes. For years I had accepted so much nonsense in tooling. Why are there so many competing compilers? Why is each one subtly forking the language? Why is our package manager a custom internal hack, and a dogshit one at that?
Why are basic things still hard to do?
The biggest thing apart from the tools I came to appreciate was a language designed for correctness. For context, I’ve never liked dynamic typing (or nulls). Dynamic typing is good for scripts, but it’s a total false economy when working on large projects. Golang proved this by demonstrating most of what people actually like about dynamic typing is really just type inferencing. I was so excited when nullable types got added to various languages because nothing says programming by coincidence like chaining together 30 functions that all have:
1
2
if (parameter is null)
throw new NullArgumentException();
I truly can’t explain how much that stuff annoys me. And yes, other languages have an equivalent to Option
or sometimes even Result
. Yes, you don’t have to use exceptions. But much in the same way it doesn’t matter if you handle memory safely, it doesn’t matter if you avoid bad alternatives when other programmers, worst of all the standard library, don’t.
Anytime I work in other languages now, I find myself sorely and immediately missing these qualities.
New Blog Post Series on Rust
Over the next few months, I’ll be covering interesting choices made in Rust. Some of them I was resistant to or dismissive of at first, but came to appreciate as I used the language more:
- Private access
- No Exceptions
- No Constructors because everything is a trait; platonic ideals
- Make errors impossible via type system (duration, ownership, etc). This No Boilerplate video covers the topic well.
There are also a bunch of design elements that I already agreed with and wanted to see:
- Rust rejects inheritance and is shamelessly object oriented without turning into design pattern soup.
- Null is not 0 and shouldn’t exist.
- Immutable as the default.
It’s not perfect though. Here are elements I disagree with. Some will get better with time, others are pretty baked into the ethos of the language and community:
- The Cult of Conciseness and “just memorize it”
- StATiC DiSpATcH and critical gaps with aliases that make generics obtuse
- The culture around macros.
In the analysis Energy Efficiency across Programming Languages Rust was just 4% slower than C and faster than C++. This is hardly the final word on the matter. As with all micro performance claims, the answer is a resounding it depends. But we can see that it’s within what could comfortably be considered the margin of error in real world applications. In other words, unless you’re working on truly esoteric tiny microcontrollers it’s almost never the case you could argue that Rust is too slow so we need to go back to C. ↩︎