Compare the assembly code generated for static vs. dynamic dispatch. We will look at how Rust uses a fat pointer for dynamic dispatch. The fat pointer consists of a data pointer to the concrete class and a pointer to the vtable. The layout of the vtable is shown below:
We will be working with the following code example:
pub trait Shape {
type T;
fn area(&self) -> Self::T;
}
pub struct Point<T> {
x: T,
y: T,
}
pub struct Rectangle<T> {
top_left: Point<T>,
bottom_right: Point<T>,
}
impl<T> Shape for Rectangle<T>
where
T: std::ops::Sub<Output = T> + std::ops::Mul<Output = T> + Copy,
{
type T = T;
fn area(&self) -> T {
let width = self.bottom_right.x - self.top_left.x;
let height = self.top_left.y - self.bottom_right.y;
width * height
}
}
pub fn area_pair_static(a: impl Shape<T = f64>, b: impl Shape<T = f64>) -> (f64, f64) {
(a.area(), b.area())
}
pub fn static_dispatch_pair(a: Rectangle<f64>, b: Rectangle<f64>) -> (f64, f64) {
area_pair_static(a, b)
}
pub fn area_pair_dynamic(a: &dyn Shape<T = f64>, b: &dyn Shape<T = f64>) -> (f64, f64) {
(a.area(), b.area())
}