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

Static vs Dynamic Dispatch

Choose between traits with static bounds and trait objects to balance flexibility and speed.

In this lesson, you will learn how to choose between the blazing speed of static dispatch and the runtime flexibility of dynamic dispatch.

When you use a trait as a generic constraint (e.g., <T: Trait>), Rust uses static dispatch. During compilation, Rust performs a process called monomorphization: it generates a unique version of your function for every specific type you use. Because the compiler knows exactly which type is being used, it can "inline" the function calls, leading to zero-overhead performance.

However, sometimes you want to store a collection of different types that all implement the same trait, such as Vec<Box<dyn Speak>>. This is dynamic dispatch. Instead of creating specialized code for every type, Rust uses a "vtable" (virtual method table)—a hidden pointer that looks up the correct method to run at runtime.

Choosing Your Tool

  • Static Dispatch (<T: Trait>): Use this by default. It is faster because the compiler knows the exact code to run, allowing for aggressive optimizations. It only breaks down if you need a collection of different types or if the compiled binary size becomes too bloated from excessive monomorphization.
  • Dynamic Dispatch (dyn Trait): Use this when you need flexibility. It allows your program to handle types that weren't even known when you wrote the code, like a plugin system where users provide their own implementations. The trade-off is a tiny bit of runtime overhead because the program must perform a lookup to find the method address.

Consider this comparison:

// Static Dispatch: Fast, generates specific code for each T
fn run_static<T: Speak>(item: T) { item.speak(); }

// Dynamic Dispatch: Flexible, works with any type implementing Speak
fn run_dynamic(item: &dyn Speak) { item.speak(); }

Static dispatch turns your traits into concrete, optimized machine code, while dynamic dispatch trades a small amount of speed for the ability to handle heterogeneous types through a pointer lookup.

Key Takeaway: Prefer static dispatch for maximum performance, and reach for dynamic dispatch only when you need the flexibility to handle multiple, different types through a single interface.