20.5 Trade-offs: Trait Objects vs. Generics
Trait objects provide runtime flexibility, but this comes at a cost compared to Rust’s compile-time polymorphism using generics:
- Runtime Performance Cost: Method calls via trait objects involve pointer indirection and a vtable lookup, which is generally slower than a direct function call or an inlined call generated through generic monomorphization. This can also impact CPU cache efficiency.
- Limited Compiler Optimizations: Because the concrete type and the specific method implementation are unknown until runtime, the compiler cannot perform optimizations like inlining across the
dyn Trait
boundary. Generics allow the compiler to create specialized versions of the code for each concrete type, enabling more aggressive optimizations. - No Direct Field Access: You cannot access the fields of the underlying concrete type directly through a trait object reference (
&dyn Trait
). The interaction is limited to the methods defined by the trait itself.
Due to these performance implications, Rust culture often favors generics (compile-time polymorphism) when the set of types is known at compile time or when performance is critical. Trait objects are used when runtime flexibility or heterogeneous collections are explicitly required.