Skip to content
tezvyn:

Static Dispatch: Zero-Cost Abstraction via Monomorphization

Source: doc.rust-lang.orgMediumHow cards are made

Static dispatch resolves function calls at compile time, avoiding runtime overhead. Rust does this via monomorphization, creating specialized code for each concrete type. This is the default for generics, but the trade-off is larger binary sizes.

Why it exists

To provide powerful abstractions like generics and traits without a runtime performance penalty. The goal is to write flexible, reusable code that runs as fast as if you had manually written a specific version for each data type.

The mental model

Think of it as a highly intelligent copy-paste operation at compile time. When you write a generic function foo<T>, you're giving the compiler a template. If you call foo with a String and a u64, the compiler creates two separate, specialized functions in the final binary, one for String and one for u64. The decision of which function to run is already made before your program starts.

How it works

The process is called monomorphization (from 'mono,' meaning one, and 'morph,' meaning form). For every generic function or type, the Rust compiler looks at where it's used in your code. For each concrete type that replaces the generic parameter (like i32 or MyStruct), the compiler generates a brand new implementation of that function with the generic parameter filled in. This means there's no generic code in the final executable, only the specialized versions. This allows the compiler to know the exact size and layout of every type at every function call.

When to use it

Static dispatch is the default and idiomatic approach in Rust. You get it for free whenever you use generics with trait bounds, like fn process<T: Display>(item: T). It's ideal when performance is paramount, as it enables the compiler to perform crucial optimizations like inlining the function call, which can eliminate the function call overhead entirely.

When not to use it

The main limitation is a lack of flexibility for heterogeneous collections. A Vec<T> can only store elements of a single, concrete type T. If you need a list containing different types that all share a common behavior (e.g., Circle and Square structs that both implement a Draw trait), you must opt into dynamic dispatch using trait objects, like Vec<Box<dyn Draw>>. The other downside is potential binary bloat; using a complex generic function with many different types can significantly increase the size of your compiled program.

One canonical example

Consider a generic function: fn duplicate<T: Clone>(x: T) -> (T, T) { (x.clone(), x.clone()) }. If your code calls this function with two different types: let pair_of_ints = duplicate(10_i32); and let pair_of_strings = duplicate(String::from("hi"));. The compiler effectively rewrites this into two separate, non-generic functions: fn duplicate_i32(x: i32) -> (i32, i32) { ... } and fn duplicate_string(x: String) -> (String, String) { ... }. Each call site then directly invokes its specialized version, with no runtime lookup required.

Interview question

What is the primary advantage of Rust's monomorphization approach for generics?

  • a.It allows for runtime type safety checks, preventing type errors during execution.
  • b.It significantly reduces the final compiled binary size by sharing generic code.
  • c.It eliminates runtime overhead by resolving all generic function calls at compile time.Correct
  • d.It enables the creation of heterogeneous collections like Vec<dyn Trait>.
Why?

Monomorphization's core benefit is to provide 'zero-cost abstractions' by generating specialized code at compile time, thus eliminating runtime overhead for generic function calls. It typically increases binary size, and heterogeneous collections require dynamic dispatch, not monomorphization.

Just read this? Test yourself on what you have been reading.

Read the original → doc.rust-lang.org

Put your scrolling time to good use

Learn one idea, try a quiz and save useful cards for revision. Tezvyn makes it easy to learn and stay current in your tech field, a few minutes at a time.

The iPhone app is on the way

We are building it. Until it lands, nothing here is held back from you: every interview card, your saved cards, streaks and the job board all work in Safari, plus hundreds of free practice quizzes of thirty questions each. Sign in and it all carries over to the app the day it arrives.

Want it as an icon? Tap Share at the bottom of Safari, then Add to Home Screen. It opens full screen and the cards you have read stay available offline.

Get it on Google PlayiPhone app coming soon

We are hiring for this. Open roles that interview on rust — each one lists the topics its interview covers.

See open roles