Static vs dynamic dispatch
- Rust course
- Advanced
- Lesson 56/81
- 4 min
Learn the difference and cost of static vs dynamic dispatch.
Static and dynamic dispatch
The same behaviour can be written in two ways:
fn statik<T: Ses>(x: &T) -> String { // a separate copy for each T
x.ses() // direct, can be inlined
}
fn dinamik(x: &dyn Ses) -> String { // a single copy
x.ses() // through the vtable
}Static: faster calls, the compiler can inline and optimize; the price is a bigger binary and compile time. Dynamic: one copy of code, mixed collections, smaller binary; the price is an indirect call and missed optimizations.
How to choose?
The default choice is generics. Switch to dyn when: you need different types in a collection, the type is decided at runtime (plugins, configuration), compile time or binary size has become a problem, or you don't want the API polluted with generic parameters. The performance difference is too small to measure in most applications; measure in hot loops.
// mixed: generics aren't enough
let v: Vec<Box<dyn Ses>> = vec![Box::new(Kedi), Box::new(Kopek)];
// single type: generics are enough
fn hepsi<T: Ses>(v: &[T]) -> Vec<String> { v.iter().map(|x| x.ses()).collect() }Practice Two dispatches
Write the statik and dinamik functions above. Call both with Kedi and print as statik: .. | dinamik: ...
Starter code
trait Ses {
fn ses(&self) -> String;
}
struct Kedi;
struct Kopek;
impl Ses for Kedi {
fn ses(&self) -> String {
String::from("Miyav")
}
}
impl Ses for Kopek {
fn ses(&self) -> String {
String::from("Hav")
}
}
fn main() {
// buraya yaz
}Sample solution
trait Ses {
fn ses(&self) -> String;
}
struct Kedi;
struct Kopek;
impl Ses for Kedi {
fn ses(&self) -> String {
String::from("Miyav")
}
}
impl Ses for Kopek {
fn ses(&self) -> String {
String::from("Hav")
}
}
fn statik<T: Ses>(x: &T) -> String {
x.ses()
}
fn dinamik(x: &dyn Ses) -> String {
x.ses()
}
fn main() {
let k = Kedi;
println!("statik: {} | dinamik: {}", statik(&k), dinamik(&k));
}Expected output
statik: Miyav | dinamik: Miyav
Questions and answers
Review the lesson questions together with their answers. To test yourself, solve the lesson interactively.
1 If a function takes <code>&dyn Ses</code>, can a <code>&Kedi</code> be passed to it?
- With as
- Yes; &Kedi converts automatically to &dyn Ses (unsize coercion) Correct answer
- No
- Only with a Box
Explanation: The compiler adds the vtable pointer in the conversion; the reverse (dyn → concrete) needs a downcast with Any.
2 Static dispatch
fn statik____(x: &T) -> String {
x.ses()
}
fn statik<T: Ses>(x: &T) -> String {
x.ses()
}
Explanation: A generic bound is static dispatch, generating a separate copy for each type.
3 Dispatch and property
| Term | Meaning |
|---|---|
Statik (generic) |
Can be inlined |
Dinamik (dyn) |
Call via vtable |
Monomorfizasyon |
A copy per type |
Unsize coercion |
&Kedi → &dyn Ses |