Static and Dynamic Dispatch
Introduction
Dispatch is the act of sending something somewhere. In computer science, this term is used to indicate the same concept in different contexts, like to dispatch a call to a function, dispatch an event to a listener, dispatch an interrupt to a handler or dispatch a process to the CPU. In this article, we will examine this term in the Object-Oriented (OO) world, which means to dispatch a call to a method.
There are two forms of dispatch, static
and dynamic
. The former means that a call to a method is resolved at compile time and the latter means that is resolved at run time. Dynamic dispatch is the mechanism that allows polymorphic operations. Together with the this
pointer, these are the tools that were built on top of the structured languages to create the object-oriented languages .
If you think about it, when you have a variable of a base class that points to an instance of a derived class, and you call a method that the child overrides, the call will be dispatched to the child. This behavior happens because OO languages dispatch calls to virtual methods dynamically. If this was not the case, then it wouldn’t possible to provide different implementations of the same definition (polymorphism).
Advantages of dynamic dispatching
- Develop plug-ins for existing products. No need to recompile the portion of code that relies on the dynamically bonded code.
- Create loosely coupled components that are easily unit tested.
- Present the same interface by using different implementations (polymorphism).
Dynamic dispatch under the hood
Most OO languages implement dynamic dispatch using Virtual Method Tables .
The idea is very simple: when you instantiate an object of a derived class, the memory allocator allocates memory for that particular object plus its parent, and a reference to this memory chunk is returned. Usually, you hold this reference on a variable.
This operation in code might look like this:
Derived derived = new Derived();
By correlating a variable of type Derived
with this memory chunk, the compiler knows how to treat this memory by getting the appropriate information from that type. If you point to the same memory chunk by using a variable of the parent type, the compiler will know how to access only the base portion of that object.
Now, let’s say that both the parent and the child are declaring a method named DoSomething
and we have the following snippet of code.
CallDoSomething(derived);
void CallDoSomething(Parent parent) {
parent.DoSomething();
}
If we don’t strive for polymorphism, then simply we want the compiler to call the DoSomething method of the parent (static dispatch
).
But, what if we strive for polymorphism?
There should be some information stored on the base portion of that object that will help the runtime to find the appropriate implementation of the DomeSomething method (dynamic dispatch
).
Most compilers implement dynamic dispatch by adding a hidden pointer on the base class that points to a special table. This table holds the memory locations of all virtual methods’ implementations. The pointer is usually called the Virtual Table Pointer
or VPTR
and the table is called the Virtual Method Table
or vtable
. This technique enables dynamic dispatch since each derived class can provide its own vtable and save a reference to it on its base portion.
The following diagram presents this idea.
As you can see, method selection is based on a single element: the type of the object or, more precisely, the this
pointer. For that reason, it’s called single dispatch
. If it was based on multiple elements, it would be called multiple dispatch
.
Dynamic dispatch limitations in most OO languages
Let’s say that we maintain an application that uses its domain models to interact with the outside world. If some complex requirements arise and we have to change the domain models without affecting the contract with the outside world, then we will have to introduce DTOs .
An easy way to map our domain models to DTOs will be to introduce a layer that will do all the mappings, like the following one.
public class Converter {
public Dto ConvertToDto(Account account) {
return new AccountDto(account.Name);
}
public Dto ConvertToDto(Purchase purchase) {
return new PurchaseDto(purchase.Balance);
}
}
After that, we can hook into the boundaries of our domain layer and use this converter.
Converter converter = new Converter();
// All domain models derive from DomainModel base class
List<DomainModel> domainModels = GetAllReturningDomainModels();
foreach (var domainModel in domainModels) {
var dto = converter.ConvertToDto(model);
// append the DTO to another list
}
// return the DTOs instead of the domain models
We solved the problem, right? This is not going to work! While virtual methods are dispatched dynamically in most OO languages, method overloading is done statically at compile time using name mangling .
As a general rule, most OO langues like C# (prior to V4) and Java, support only single dispatch in the form of virtual methods.
To solve that problem you may use the visitor pattern . This pattern simulates a double dispatch by dispatching two method calls. Some OO languages have built-in support for double dispatch like C# (from V4) using the dynamic
keyword. It’s worth mentioning that these languages achieve double dispatch by dispatching only one method call.