Rust is perfectly imperfect

Author: Wojciech Muła
Added on:2026-01-08
2026-01-08-imperfect-rust/2Q6A1876_small.jpg

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.

  1. First of all, bringing the toolchain – which contains the compiler, linker, standard library, documentation and package manager — is seamless with rustup.
  2. 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.
  3. 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.
  4. 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.
  5. 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.
  6. 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.
  7. Generics, called in C++ as “templates”, are built into the language and their use is mostly not different than using regular types/functions.
  8. 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.
  9. Feature flags are built in the whole ecosystem.
  10. The tools for documenting code are built in. There’s no difference in documentation generated for standard library and any other package.
  11. 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.