Static Dispatch
What it is
- The function implementation is chosen at compile time
- Used by generics (
T: Trait,impl Trait)
How it works
- The compiler monomorphizes generic code
- A separate, concrete version of the function is generated for each type
- All types and sizes are known at compile time
Properties
- No runtime dispatch cost
- Function calls can be inlined
- Enables aggressive optimizations
- Larger binaries (more generated code)
example:
fn sum<I: Iterator<Item = i32>>(iter: I) -> i32 {
iter.sum()
}
Use when
- Performance matters
- Code is in hot loops
- Working with iterators or parallel code (e.g. Rayon)
Rayon: almost always static dispatch
Dynamic Dispatch
What it is
- The function implementation is chosen at runtime
- Used by trait objects (
dyn Trait)
How it works
- A single function body is compiled
- Method calls go through a vtable
- The concrete type is erased inside the function
Properties
- Runtime cost (indirect function call)
- No inlining of trait methods
- Smaller binaries
- Allows heterogeneous types at runtime
fn sum(iter: &mut dyn Iterator<Item = i32>) -> i32 {
iter.sum()
}
Use when
- The concrete type is not known at compile time
- You need runtime polymorphism
- You need to store or return different implementations via one interface
Important clarifications
dyndoes not imply heap allocation- Heap allocation happens only with owning pointers like
Box<dyn Trait> &dyn Traituses no heap
what is function call site: the code where the function is called.
how the compiler handle generics?
This is called monomorphization. For a function call, the compiler check the the call site, get each type fits into the generic type, and generate a version of the function automatically that only for that specific type.
Monomorphization = replacing generic code with concrete, type-specific code at compile time.
Generics let the programmer describe a family of functions parameterized by types, and the compiler expands that family into concrete, type-specific implementations wherever they’re needed.
Because it is compile time, so it allows:
exact type sizes
stack allocation
zero runtime overhead
full optimization