Introduction
Generics use static dispatch, resolved at compile time via monomorphization. Sometimes you need to store or pass around values of different concrete types that share a trait, decided only at runtime — for example, a vector of different shapes that all implement a Draw trait. Rust solves this with trait objects, written as dyn Trait, which use dynamic dispatch through a vtable instead of generating specialized code per type.
Cricket analogy: Static dispatch via generics is like a team practicing a pre-planned play for a specific known bowler; dynamic dispatch with dyn Draw is like a fielding captain deciding the field placement on the fly at runtime for whichever batter is actually at the crease, chosen from a mixed lineup of styles.
Syntax
trait Draw {
fn draw(&self);
}
fn render(item: &dyn Draw) {
item.draw();
}
let shapes: Vec<Box<dyn Draw>> = vec![
Box::new(Circle {}),
Box::new(Square {}),
];Explanation
&dyn Trait and Box<dyn Trait> are trait objects: fat pointers that carry both a pointer to the data and a pointer to a vtable of method implementations. Calling a method on a trait object looks up the function in the vtable at runtime, which costs an indirect call compared to the direct, inlined call generics produce. Trait objects must be 'object safe', which roughly means the trait has no generic methods and no methods that return Self by value, since the concrete size and type are erased. Box<dyn Trait> is commonly used to store heterogeneous collections of types that all implement the same trait.
Cricket analogy: Box<dyn Draw> is like a fat envelope handed to the umpire containing both a player's ID card and a rulebook page telling the umpire which sport's rules apply; consulting that rulebook at every decision costs a beat longer than an umpire who already knows the one sport being played.
Example
trait Draw {
fn draw(&self);
}
struct Circle;
struct Square;
impl Draw for Circle {
fn draw(&self) {
println!("Drawing a circle");
}
}
impl Draw for Square {
fn draw(&self) {
println!("Drawing a square");
}
}
fn main() {
let shapes: Vec<Box<dyn Draw>> = vec![Box::new(Circle), Box::new(Square)];
for shape in shapes.iter() {
shape.draw();
}
}Output
Drawing a circle
Drawing a squareKey Takeaways
dyn Traitenables dynamic dispatch via a vtable, resolved at runtime.- Generics use static dispatch (monomorphization), trait objects use dynamic dispatch — a real tradeoff in performance vs flexibility.
Box<dyn Trait>or&dyn Traitallow storing heterogeneous types that share a trait in one collection.- A trait must be 'object safe' to be used as a trait object — no generic methods, no returning
Selfby value. - Trait objects are fat pointers: data pointer plus vtable pointer.
Practice what you learned
1. What mechanism does `dyn Trait` use to call methods at runtime?
2. How does dynamic dispatch compare to the static dispatch used by generics?
3. What is required for a trait to be used as a trait object (`dyn Trait`)?
4. Which type is commonly used to store a heterogeneous collection of types implementing the same trait?
5. What does a trait object like `&dyn Draw` consist of internally?
Was this page helpful?
You May Also Like
Traits in Rust
Traits define shared behavior that types can implement, similar to interfaces in other languages.
Generics in Rust
Generics let you write functions, structs, and enums that work over many types while remaining zero-cost at runtime.
Default Trait Implementations in Rust
Trait methods can provide a default body that implementers may use as-is or override with custom behavior.
Structs in Rust
Structs let you group related values into a single named type with fields you access by name.
Related Reading
Related Study Notes in Programming
Browse all study notesApache Spark Study Notes
Programming · 30 topics
ProgrammingApache Flink Study Notes
Programming · 30 topics
ProgrammingHadoop Study Notes
Programming · 30 topics
ProgrammingSnowflake Study Notes
Programming · 30 topics
ProgrammingApache Airflow Study Notes
Programming · 30 topics
Programmingdbt (Data Build Tool) Study Notes
Programming · 30 topics