Back to TIL 2026-01-06

Zero-cost abstraction principle in Rust

What is a "Zero-Cost Abstraction"?

In many high-level languages, adding a layer of abstraction (like an interface, a wrapper, or a collection) usually comes with a "tax"—extra memory usage or slower execution because the computer has more work to do at runtime.

Bjarne Stroustrup (the creator of C++) defined the principle that Rust follows religiously:

What you don't use, you don't pay for. (No overhead for features you aren't using).

What you do use, you couldn't hand-code any better. (The abstraction compiles down to the same efficient machine code as a manual implementation).

How Rust Pulls This Off

Rust achieves this primarily through its clever compiler and two specific features: Generics (with Monomorphization) and Ownership/Borrowing.

1. Monomorphization (The "Secret Sauce")

When you use a generic function in Rust, the compiler doesn't just treat everything like an "Object" (like Java might). Instead, it looks at every place you called that function and generates a specialized version for each specific type.

Example: If you have a function print_it<T>(item: T), and you call it with an i32 and a String, the compiler literally writes two separate functions behind the scenes. At runtime, there is no "searching" for the right type; the code just runs directly.

2. Iterators

This is the most famous example. You can chain methods like map, filter, and fold. In Python or JS, this might create multiple intermediate lists. In Rust, these are compiled into a single, tight assembly loop—exactly like a manual for loop.

let numbers = vec![1, 2, 3, 4, 5];

// This looks high-level, but compiles to the same speed as a manual loop!
let sum: i32 = numbers.iter()
    .filter(|&x| x % 2 == 0)
    .map(|&x| x * 2)
    .sum();

Why This Matters