Rust is perfectly imperfect
| Author: |
Wojciech Muła |
| Added on: | 2026-01-08 |
My sampling of the real world is performed via X, formerly Twitter. And as of
the end of 2025, it appears that Rust is the most hated language ever. I
noticed that the C and C++ programmers constitute the majority of Rust critics.
Despite the critics, Rust is having its momentum — more and more companies are
adopting Rust, trying to create new pieces of software using it or just
rewriting their software. There are also sporadic opposite moves, that is
getting back to C or C++.
I was thinking about these strong, anti-Rust sentiments and — more importantly
— why people want to use Rust. The anti-Rust sentiments seem to me to be more
of a social problem caused by individuals, and since I am rarely involved in
"community" life and seldom read any comments, I don’t feel like I have
anything interesting to add. Let me share my thoughts about the latter issue.
From the perspective of language programming theory, Rust added nothing.
Literally, there’s nothing new in it. Of course, someone might shout “THE
BORROW CHECKER” — but the borrow checker is just more advanced liveness
analysis.
Rust did something that many other programming languages tried in the past but
had failed to deliver. It is easy to use thanks to its consistency and
predictability. And it was achieved by Rust as the whole, not only the
language itself.
- First of all, bringing the toolchain – which contains the compiler, linker,
standard library, documentation and package manager — is seamless with
rustup.
- The package manager, cargo, makes it easy to tame dependencies. And it works
with third-party packages as well as local ones. From the programmer point of
view there’s no difference whether they use “local” or “remote” packages. It’s
also easy to point out the path where the given package is located, so with
established dependencies, the internet connection is not needed.
- The standard library provides sufficiently powerful entities to produce a
decent program, although it is not as rich as Python's one. But all basic,
numeric data types come with a handful of useful methods and constants. Strings
are by default UTF-8 encoded ones, also with a rich set of methods. There are
also popular containers: resizable vectors, maps and sets (both key-ordered and
hash-based). There are interfaces to the underlying OS: we can work with a file
system, network, threading and timers.
- The language comes with a small, strong type system. There are arrays,
tuples, and structures and, the most important element of the type system,
algebraic data types, called for an unknown reason “enums”. Algebraic data
types remove the need of introducing hierarchies of types in 99% cases —
complex structures are naturally expressed with “enums”. Even using interfaces
(called in Rust “traits”) is not needed. Apart from libraries, when we work on
regular software, we usually know all types in advance, or the rate of
introducing new types is relatively slow.
- The language supports two special kinds of enums: Option (value or
null/nil/none) and Result (value or error). The types come with a couple of
methods that eases their usage, for instance returning default value when
option is none. The standard library uses these enums everywhere, and their
usage is ubiquitous and feels natural.
- Rust allows us to generate code based on annotations, this is a kind of
compile-time reflection. These code generators are written in Rust. This
feature allows programmers to extend their types with extra methods or
implement some boring parts of code. Think about serialization, for instance.
- Generics, called in C++ as “templates”, are built into the language and
their use is mostly not different than using regular types/functions.
- The language introduces the traits, called in Java as “interfaces”, that
enable two important programming constructions: abstract data types and
restricting template arguments, acting as C++’s concepts. When we need to
interface with other-programmer-defined code, we use traits. Traits are also
practical: they allow not only to define an abstract API, but also provide
default implementations. Oh, and traits can extend other traits.
- Feature flags are built in the whole ecosystem.
- The tools for documenting code are built in. There’s no difference in
documentation generated for standard library and any other package.
- Rust is also aware of situations where we don’t work under any OS (so
called “baremetal”) or we are an OS. Then a single declaration no_std
disable linking with the standard library — yet keep providing some
OS-independent types and functions via crate “core”.
These are the major factors that make Rust ecosystem composable. I’m not really
convinced that Rust’s safety is the primary criteria of choosing the language.
For sure, Rust makes it hard to introduce memory-related bugs, but there is
still a huge area where bugs are possible. Well, if people really needed safety
in their system, they would use functional languages, theorem provers and other
sophisticated tools or methods to assure software is safe in all possible
attack or malfunction directions. The C and C++ world already have quite a nice
set of tools helping in catching different kinds of bugs, for instance fuzzers,
runtime checkers like address sanitizers or valgrind.
Rust, similarly to functional languages, allows a programmer to focus on their
problem: if your code compiles, it likely will work.
But in my opinion Rust brings back the joy of programming in an imperative paradigm.
Thank you for reading.
Acknowledgements: I’d like to thank Daniel Lemire, Dan Shechter and
Romek Kurc for reading the draft of this text and sharing their corrections
and thoughts.