The Design: No Exceptions
You know the try-catch that silently swallowed an error? The one where the catch block logged a message nobody read, and the application continued in an undefined state for forty minutes before someone noticed?
Functions that can fail in Rust return Result<T, E>: either Ok(value) or Err(error). The failure path is visible in the function's type signature. Every caller knows that the function can fail. Every caller must handle the failure or explicitly propagate it with the ? operator.
There are no hidden throws. No catch blocks that swallow errors silently. No stack unwinding that crosses function boundaries invisibly. No "everything is fine" until a try-catch three levels up catches something it does not understand and logs "An error occurred." One does wonder how many production incidents have begun with that exact log message.
The ? operator makes error propagation ergonomic:
fn read_config(path: &str) -> Result<Config, Error> {
let contents = fs::read_to_string(path)?;
let config: Config = toml::from_str(&contents)?;
Ok(config)
}
Each ? either unwraps the success or returns the error to the caller. The code reads linearly. The error handling is explicit. The types tell the truth. Quite the novelty.
The Design: No Inheritance
You know the six-level class hierarchy where nobody remembers what the grandparent overrides? The one where changing the parent class broke seventeen subclasses in ways that only appeared in integration testing?
Rust has no class inheritance. No extends. No class Dog extends Animal. No hierarchy where the behaviour of your object depends on decisions made four levels above by someone who left the company in 2019.
Instead, Rust uses traits: shared behaviour defined as interfaces, implemented by types. A struct can implement as many traits as it needs. Traits compose. They do not cascade.
There is no diamond problem. No fragile base class. No "I changed the parent class and now everything behaves differently." The relationship between types is explicit: this type implements this behaviour. Full stop. One does rather miss problems one never has.
This is composition over inheritance, enforced by the language. Not a design pattern you choose to follow when you remember. A constraint the compiler imposes whether you remember or not.
The Design: No Implicit Mutability
In Rust, all variables are immutable by default. To make something mutable, you write let mut. The act of changing state becomes a conscious, visible decision in the code. Not a default. A declaration.
Combined with the borrow checker's rule that you cannot have a mutable reference and an immutable reference to the same data at the same time, this eliminates data races at compile time. Not by detecting them at runtime. Not by crashing when they occur. By making them structurally impossible to express.
Every concurrent bug you have ever debugged, every "it works on my machine" that vanished under load, every race condition that appeared once in ten thousand runs: Rust's type system prevents them by refusing to compile code that could produce them. The compiler does not trust you. It is, one must concede, entirely justified.
The Trade-Off
Let us be honest. The learning curve is real and well-documented.
The borrow checker will reject code that compiles without complaint in every other language you know. It will reject code that is, in fact, correct. It will reject code that has no bug. It will reject code because it cannot prove the code has no bug, and Rust has decided that "cannot prove safe" is the same as "unsafe."
This is frustrating. It feels adversarial. It feels like the compiler is wrong and you are right and the code is fine and why will it not just compile.
It is not wrong. It is conservative. And in the gap between "probably correct" and "provably correct" lie the bugs you would have shipped to production, discovered at 3 AM, and spent three days debugging whilst questioning your career choices.
The Rust community is honest about this cost. The first three months are painful. The compiler's error messages are unusually good (it tells you what went wrong and often suggests the fix), but the frequency of those messages during learning is high. You will argue with the compiler. You will lose. You will, eventually, realise that losing to the compiler is considerably cheaper than losing to production.
The reward: once it compiles, it works. Not always. But with a frequency and reliability that other systems languages do not match. The category of bugs that Rust eliminates (use-after-free, null dereference, data races, buffer overflows) accounts for approximately 70% of all security vulnerabilities in C and C++ codebases, according to research from Microsoft and Google's Project Zero. Seventy percent. One does find that number rather difficult to ignore.
The Proof
The Linux kernel accepted Rust as a supported language in December 2025. It is no longer experimental. Dave Airlie, maintainer of the DRM subsystem, stated that the DRM project was approximately one year away from requiring Rust and disallowing C for new drivers. The kernel contains 34 million lines of C and 25 thousand lines of Rust. The transition has begun. One does note the ratio with a certain quiet patience.
Microsoft has rewritten 188,000 lines of Windows kernel and DirectWrite code in Rust, with a stated ambition to eliminate C and C++ from its entire codebase by 2030. When Microsoft, a company not traditionally associated with radical architectural courage, decides to rewrite its kernel in a new language, one does pay attention.
Discord's Go-to-Rust migration eliminated garbage collector latency spikes and reduced response time from milliseconds to microseconds. The blog post has become required reading in systems engineering circles. Quite deservedly.
Cloudflare built Infire, a custom LLM inference engine, in Rust, achieving 7% faster inference than vLLM. AWS, Google, and Meta all run Rust in production at significant scale.
Android 16 ships with Rust-built components in the kernel (ashmem memory allocator). Millions of devices run Rust in production without their owners knowing or caring. Which is, of course, exactly how infrastructure should work.
45% of enterprises now run Rust in non-trivial production workloads. The Stack Overflow Developer Survey has named Rust the most admired language for nine consecutive years, with an 83% admiration rate in 2024. Not because it is easy. Not because the learning curve is gentle. Because the elevator stops crashing.
The Principle
Every feature a language grants is a failure mode it accepts. Every convenience added is a bug category normalised. Every "yes" comes with a cost that compounds over decades, paid not by the language designer but by every developer who inherits the codebase.
The courage to say no is the rarest engineering virtue. Rust proves that a language can refuse convenience, refuse familiar patterns, refuse the features that every other language considers mandatory, and win adoption not despite the refusal but because of it.
The borrow checker is not a barrier. It is a boundary. And boundaries, applied with discipline, are what separate systems that survive from systems that merely ship.
Graydon Hoare's elevator still works. One rather suspects it is no longer written in C.
Graydon Hoare stepped down from Rust in 2013. The language he started in frustration on a stairwell is now in the Linux kernel, the Windows kernel, and the infrastructure of every major cloud provider. The fungus, it turns out, was indeed over-engineered for survival.
Read the full article on vivianvoss.net →
By Vivian Voss — System Architect & Software Developer. Follow me on LinkedIn for daily technical writing.