Cloud Parts

Static or dynamic dispatch?

DimensionStatic dispatchDynamic dispatch
Who picks the functionThe compiler, from the types it seesThe running program, from the object the call is made on
What a call costsA direct call, or none at all once inlinedA load from a table (vtable, itable) and an indirect call
OptimizationThe optimizer can inline and optimize across the callBlocks inlining, unless a JIT sees one type in practice and inlines speculatively
Compiled codeOne copy per type (monomorphization), so bigger binaries and slower buildsOne copy serves every type
Mixed-type collectionsNo: a Vec<T> holds one typeYes: a Vec<Box<dyn Shape>> holds circles and squares together
Types added laterMust exist when the program is compiledPlugins, subclasses and test fakes work without recompiling the caller
In codeOverloads, C++ templates, Rust generics (fn f<T: Trait>), Go generics (partly)C++ virtual, Rust dyn Trait, Go interfaces, Java and C# interfaces and virtual methods, Python and JavaScript method calls

Rule of thumb

Default to static dispatch for code on the hot path where every type is known, and to dynamic dispatch where flexibility matters more than a few nanoseconds per call: plugin systems, heterogeneous lists, dependency injection, tests. Many designs mix them: a generic inner loop called from a dyn interface at the edge, or a C++ template that shares its non-generic core through a base class. Measure before switching; JITs such as HotSpot often remove the cost of virtual calls that only ever see one type.

Sources