Course contentsShow
← Rust
Lesson 57 of 1,9101. Rust Fundamentals and ToolingFree lesson

Generics and Monomorphization

Analyze the performance trade-offs of generic code generation versus dynamic dispatch.

In this lesson, you will learn how Rust’s "monomorphization" process achieves high-performance execution by generating specialized code for every type you use with a generic function.

How Monomorphization Works

When you write a generic function, such as fn identify<T>(item: T), you are writing a template. Rust does not compile this into one "do-it-all" function that handles any type. Instead, every time you call identify(5) (with an i32) and identify("Rust") (with a &str), the compiler performs monomorphization. It creates two distinct versions of the function—one specialized for i32 and one for &str—and compiles them separately.

Performance Trade-offs

Because the compiler knows the exact concrete types at each call site, it can perform aggressive optimizations, such as "inlining" the code directly into the caller. This results in execution speeds identical to writing the functions by hand.

However, this comes at a cost: Binary Bloat. If you use a generic function with 50 different types, the compiler will generate 50 separate copies of that code inside your final program. This increases the size of your executable, which can impact instruction cache efficiency.

Contrast with Dynamic Dispatch

To avoid this code duplication, some languages use "dynamic dispatch," where the computer looks up the function logic at runtime using a pointer. Rust gives you a choice:

  • Generics (Monomorphization): Faster execution because the CPU knows exactly what it is running, but larger binary size.
  • Dynamic Dispatch (Trait Objects): Smaller binary size, but slightly slower at runtime because the CPU must perform a lookup to find the correct method to execute.

Consider this generic function:

fn process<T: Display>(item: T) {
    println!("{}", item);
}

If you call process(10) and process(20), Rust generates two specialized machine code blocks. The CPU executes them as if you had written process_i32 and process_i32 specifically, eliminating any "guesswork" at runtime.

Key Takeaway: Monomorphization turns generic templates into specialized, lightning-fast machine code at the expense of increasing the total size of your compiled program.