Why Rust is different, with Alice Ryhl

The Pragmatic Engineer 1h5 8 min #87
Why Rust is different, with Alice Ryhl
Watch on YouTube

Summary

  • Rust is a systems programming language that has surged in popularity by offering something rare: the reliability of high-level languages with the performance of low-level ones. It eliminates entire categories of bugs at compile time—memory safety vulnerabilities, null pointer errors, unhandled exceptions, and forgotten enum variants—making it increasingly attractive for backends, CLI tools, embedded systems, and even the Linux kernel. Alice Ryhl, a Google Android Rust team engineer, Tokio core maintainer, and Rust language team adviser, walks through what makes Rust different, how it’s governed, and why engineers say “if it compiles, it works.”

Why Rust: the core pitch

  • Reliability through the compiler, not discipline. Rust’s type system and ownership model catch bugs at compile time that other languages only catch at runtime—or never. This is the central pitch: you spend more time satisfying the compiler upfront, but once it builds, whole classes of bugs are simply impossible.

    • No null. Rust uses an Option enum instead. You must explicitly handle the None case before using a value, eliminating the “billion-dollar mistake” that plagues Java, C++, and others.
    • Errors as values, not exceptions. Functions return a Result type (either success or error), and the ? operator makes error propagation concise. Forgetting to handle an error is a compiler error.
    • Exhaustive pattern matching. When you match on an enum, the compiler requires every variant to be handled. Adding a new variant later forces you to update every match statement across the codebase—making refactoring safe.
    • No uninitialized variables. The compiler forces you to assign a value before first use.
    • Documentation examples are tests. Code examples in Rust docs (/// comments) are compiled and run as tests. If your code changes break an example, the build fails—solving the perennial problem of stale documentation.
    • JSON and input validation. Libraries like Serde let you derive deserialization code from struct definitions, generating efficient, type-safe parsing that rejects malformed input at the type level.
  • Memory safety without a garbage collector. This is Rust’s most distinctive technical achievement and the reason it’s being adopted in the Linux kernel and other C/C++ domains.

    • In C++, trivial mistakes like off-by-one errors or use-after-free become security vulnerabilities. Attackers can exploit these to escalate privileges (e.g., writing a zero to a user ID field to become root).
    • Rust’s ownership and borrowing system guarantees memory safety at compile time: no dangling pointers, no double-frees, no data races—without the runtime cost of garbage collection.
    • This matters for embedded systems and kernels where GC is unacceptable, and for backends where GC pauses cause latency spikes.
  • Performance without garbage collection. Rust cleans up objects when they go out of scope (deterministic destruction), avoiding the unpredictable pauses of garbage-collected languages like Java or C#. This makes it viable for both low-level systems programming and high-performance backend services.

Ownership, borrowing, and the borrow checker

  • Ownership model. Every value has exactly one owner. When you assign let b = a, the value is moved from a to b, and a becomes invalid. This prevents double-free errors and makes cleanup deterministic.

    • This is the single biggest conceptual shift for developers coming from garbage-collected languages. You cannot freely alias data; the compiler enforces exclusive ownership.
  • References and borrowing. Instead of moving a value, you can borrow it with a reference (&T). The borrow checker ensures that:

    • You can have any number of immutable readers or one mutable writer, but not both simultaneously.
    • References cannot outlive the data they point to.
    • This is checked entirely at compile time with zero runtime cost.
  • Fighting the borrow checker. Newcomers often struggle when the compiler rejects code that “should work.” The solution is usually not to change the code but to restructure the data—avoiding cyclic references, using Arc (atomic reference counting) for shared ownership, or redesigning the data layout as a tree or DAG.

  • Pointer types for different needs.

    • &T / &mut T: borrowed references, checked at compile time.
    • Arc<T>: atomic reference counting for shared ownership across threads.
    • Rc<T>: non-thread-safe reference counting for single-threaded contexts.
    • Raw pointers (*const T, *mut T): used only in unsafe blocks.

Unsafe: the escape hatch

  • unsafe is not a way to disable the compiler’s checks. It unlocks a small set of additional operations (raw pointer dereferencing, calling external functions, accessing mutable statics) that the compiler cannot verify. The borrow checker still runs.
    • Each unsafe operation has documented invariants that the programmer must uphold. Violating them causes undefined behavior.
    • Legitimate uses of unsafe:
      • Building safe abstractions. The standard library’s Vec is built on unsafe internally (raw memory allocation, pointer arithmetic) but exposes a completely safe API. If the API is correctly designed, users can never trigger memory unsafety.
      • Calling C libraries. Rust can interface with C code, wrapping unsafe FFI calls in safe APIs.
      • Performance-critical code. Functions like get_unchecked skip bounds checking when the programmer can prove safety (e.g., inside a loop where the index is already validated).
    • A typical backend server would use zero unsafe. It’s primarily a tool for library authors and systems programmers.

The Rust ecosystem: Cargo and crates

  • Cargo is Rust’s all-in-one build tool: it compiles code (cargo run), manages dependencies, runs tests (cargo test), generates documentation (cargo doc), and runs benchmarks. Unlike pip or npm, dependencies are resolved locally per project—no global installs or virtual environments needed (though a shared registry cache avoids redundant downloads).
  • Crates are Rust’s packages, published to crates.io. The ecosystem is mature for backends, CLI tools, embedded systems, and systems programming. The least mature area is frontend—compiling Rust to WebAssembly for browser use is possible but not yet a compelling replacement for TypeScript.
  • Security concerns. Like any package manager, Cargo is theoretically vulnerable to supply-chain attacks (compromised maintainer accounts, malicious crates). The Rust team actively removes malicious crates, but the problem is fundamentally hard and not unique to Cargo.

How Rust is governed

  • No benevolent dictator. Unlike Python (Guido van Rossum historically) or Linux (Linus Torvalds), Rust has no single leader. Decisions are made by teams: the language team, the library API team, the compiler team, and others.

    • Teams self-organize and delegate well. A decision about the standard library API is deferred to the library team; a language feature goes to the language team.
    • Contentious decisions are often discussed in person at Rust All Hands (an annual gathering of core contributors).
  • RFC process for major changes. A Request for Comment (RFC) is a structured document with:

    • Summary and motivation for the feature.
    • Guide-level explanation (written as a tutorial, as if the feature already existed).
    • Reference-level explanation (written as formal documentation).
    • Rationale and alternatives (why this design over others).
    • Prior art (what C++, Java, etc. do).
    • Future possibilities.
    • This structure forces authors to think from the user’s perspective before writing code—similar to Amazon’s practice of writing a press release before building a product.
  • Final Comment Period (FCP). After a team approves an RFC, a bot creates a GitHub issue with a checkbox for each team member. Once all but at most two members have checked off, a two-week FCP begins. Team members can file concerns that pause the process until resolved. After two weeks with no unresolved concerns, the RFC is accepted.

  • Smaller decisions use lighter processes.

    • ACP (API Change Proposal): a GitHub issue for adding a function or type to the standard library.
    • MCP (Major Change Proposal): used by the compiler team for changes big enough to need discussion but not a full RFC (e.g., a new compiler flag).
  • Nightly → stabilization pipeline. New features are implemented behind a feature flag on the nightly compiler. Once ready, a stabilization report documents edge cases and tests. After another FCP, the feature flag is removed. It appears in the next beta release and becomes stable six weeks later.

  • Editions, not versions. Rust uses editions (2015, 2018, 2021, 2024) instead of major version numbers. Different crates in the same project can use different editions and still work together seamlessly.

    • Editions allow breaking syntax changes (e.g., async/await was introduced in the 2018 edition) without fragmenting the ecosystem. Old code keeps working forever.
    • This is fundamentally different from Python 2→3: you can incrementally migrate individual crates rather than rewriting everything at once.

Rust in the Linux kernel

  • Rust is no longer experimental in the Linux kernel. At the December 2025 Linux Kernel Maintainer Summit, it was officially decided that Rust has the same standing as C—a major milestone after years of heated debate.
    • The pitch is straightforward: C’s memory safety vulnerabilities are a constant source of security exploits. Rust eliminates them while still allowing unsafe for the low-level operations the kernel needs.
    • Adoption is accelerating. At each successive Linux Plumbers Conference, more kernel subsystems have started using Rust—from “that’s a nice experiment” to “we have Rust code in production.”
    • Government regulations (e.g., from US agencies) are pushing against non-memory-safe languages for security-sensitive systems, further incentivizing Rust adoption.

AI and Rust

  • Rust may be uniquely well-suited for AI-assisted development. Because the compiler provides immediate, precise feedback, AI coding agents can iterate: generate code, check if it compiles, fix errors, and repeat. This is harder in languages where bugs only surface at runtime.
    • Alice uses AI tools (like Gemini CLI) for tasks she finds tedious—writing benchmarks, modifying build scripts, generating boilerplate. The AI handles the toil; she reviews the output.
    • AI for code review in the kernel. At the Linux Kernel Maintainer Summit, there was discussion of bots that feed patch submissions into AI agents for automated review. Linus and others found the reviews impressively useful—not as a replacement for human review, but as an additional safety net.
    • Risk of false understanding. AI can generate Rust code that compiles without the developer understanding why it works. For a language where data structure design is critical, this is dangerous. Learning the ownership model properly is essential.

Getting started with Rust

  • The Rust Book (official, free online) is the recommended starting point.
    • It’s called a “book” even though it’s a web tutorial—a playful Rust convention.
  • Rustlings provides small, incomplete Rust programs for you to fix—a hands-on way to learn.
  • John Gjengset’s book is aimed at intermediate Rust developers who have the basics down and want to go deeper.
  • Build a project. The best way to learn is to implement something real—a web server, a CLI tool, a small service.
  • Contributing to Rust:
    • The Rust project uses Zulip as its chat server—a good place to ask questions and find mentorship.
    • The Rust for Linux project has a contributing page with links to drivers and issue trackers.
    • You can contribute indirectly by implementing language features needed for kernel work, or by working on Rust-in-GCC.

Why Rust is growing now

  • It fills a gap that didn’t exist before. Previously, you chose between reliable (Java, Go, Python—with GC) and performant (C, C++—unsafe). Rust is the first language to credibly offer both.
    • This makes it attractive for backends (reliable servers without GC pauses), embedded systems (safe firmware), systems programming (kernel modules), and CLI tools (fast, correct, easy to distribute).
  • Regulatory pressure is pushing organizations away from C/C++ for security-critical code.
  • The ecosystem has reached a tipping point. Mature async runtimes (Tokio), web frameworks, serialization libraries, and growing corporate investment (Google, Microsoft, AWS, Oxide) mean Rust is no longer a niche experiment—it’s production-ready.
Back to The Pragmatic Engineer