Course contentsShow
← Rust
Lesson 693 of 1,9106. Generics and Static DispatchFree lesson

Generic Trait Objects vs Static Dispatch

Distinguish between the performance characteristics of trait objects and static generic dispatch.

In this lesson, you will learn how to choose between the performance benefits of static dispatch and the runtime flexibility of trait objects.

When you use generic type parameters with trait bounds, like fn process<T: Speak>(item: T), Rust performs static dispatch. During compilation, the compiler looks at every place you call process and generates a specific version of that function for every concrete type used. This process, called monomorphization, allows the compiler to "see" exactly which code is running, enabling it to inline function calls and remove overhead entirely. It is extremely fast, but it forces the compiler to generate more code, which can increase your binary size.

In contrast, trait objects (using the &dyn Trait syntax) provide dynamic dispatch. When you use fn process(item: &dyn Speak), the compiler no longer creates a specialized version for every type. Instead, it creates a single function that interacts with a "vtable" (a lookup table of function pointers). At runtime, the program looks at the vtable to figure out which implementation of speak to execute.

The Performance Trade-off

  • Static Dispatch (T: Trait): The compiler generates code tailored to the specific type. It is usually faster because the CPU can predict branches easily and inline code, but it creates "code bloat" as the number of types grows.
  • Dynamic Dispatch (&dyn Trait): The program is more flexible—you can store a list of different types in a single Vec<Box<dyn Trait>>—but it incurs a small runtime cost due to the pointer indirection and the inability for the compiler to inline the calls.

Consider this: if you need a high-performance system where speed is critical, prefer static dispatch. If you need a heterogeneous collection where you want to store many different types that share a common behavior, use trait objects to gain the flexibility that static generics cannot provide.

Key Takeaway: Static dispatch trades binary size for raw performance through monomorphization, while dynamic dispatch uses trait objects to trade a small amount of runtime speed for greater structural flexibility.