Dispatch is the mechanism for selecting a specific function (method) to call. Rust has two approaches: static and dynamic dispatch.
Background:
In OOP languages, dynamic method calls typically use a vtable (virtual table). Rust implements a similar mechanism for trait objects — references to objects of types that implement certain traits. Static dispatch occurs when using generics and trait bounds.
Problem:
Often, one has to choose between flexibility (the ability to work with objects of different types through a single interface) and performance (static dispatch allows for inlining methods). An incorrect choice leads either to overly complex generics or performance losses.
Solution:
Static dispatch is achieved through generic parameters: the compiler generates separate code for each type. Dynamic dispatch occurs if a function takes an argument of type &dyn Trait or Box<dyn Trait>, then when calling a method by trait Rust looks in the vtable by address, as in classic OOP languages.
Code example:
trait Shape { fn area(&self) -> f64; } impl Shape for Circle { fn area(&self) -> f64 { 3.1415 * self.radius * self.radius } } fn print_area(shape: &dyn Shape) { // dynamic dispatch println!("area = {}", shape.area()); } // Or statically: fn print_area_static<S: Shape>(shape: &S) { println!("area = {}", shape.area()); }
Key features:
dyn Trait uses vtable (dynamic dispatch)Can you make Box<dyn Sized>?
No. dyn Trait is by definition unsized, always requires the use of Box, Arc, or references, but not 'Box<dyn Sized>' — this makes no sense. Sized traits are not possessed by trait objects.
Is dyn Trait allowed for traits with generic methods?
No. You cannot create object-safe traits with generic methods (this is often confused!); composite types are not object-safe:
trait MyTrait { fn foo<T>(&self, x: T); } let x: &dyn MyTrait = ... // Compilation error!
Can you make dyn Trait for a trait with Self values in the signature?
No, if the method returns Self (many do not understand this nuance: object safety requires that Self not be in the signature; self can only be in arguments, but not in the return value).
Everywhere dyn Trait was used for interface universality, even inside tight loops where generics could suffice.
Pros:
Cons:
Static dispatch was used in the internal logic, while dyn Trait was used only at the boundaries of modules.
Pros:
Cons: