Every Rust thread eventually gets to the same argument: generics give you zero-cost static dispatch, dyn Trait costs you a vtable lookup, therefore generics are faster. True, and also frequently irrelevant. I got tired of repeating the folklore, so I measured it.
The setup is deliberately dull. A Shape trait with one area(&self) -> f64, two impls, a vector of a million of them, and two consumers: one generic over T: Shape, one taking &dyn Shape. Criterion, release build, target-cpu=native.
fn sum_generic<T: Shape>(xs: &[T]) -> f64 {
xs.iter().map(|s| s.area()).sum()
}
fn sum_dyn(xs: &[Box<dyn Shape>]) -> f64 {
xs.iter().map(|s| s.area()).sum()
}
The generic version came in around 0.9 ms over the million elements. The dyn version, about 1.4 ms. So yes, the trait object is slower, by roughly half on this microbenchmark. That sounds dramatic until you notice we are talking about an extra half-nanosecond per call, and that the dispatch cost is mostly the indirect branch defeating the prefetcher, not the vtable load itself.
The honest conclusion is the boring one. If you are summing a million tiny areas in a hot loop, reach for generics and let the optimiser inline everything. If you are dispatching to one of three handlers a few thousand times a request, dyn is free in any sense that matters, and it keeps your binary smaller and your compile times sane. Measure your own loop before you let an internet argument shape your architecture.