Pattern: Double Dispatch


Context

When a message with a parameter is sent to an object, the resultant behaviour is defined by the implementation of that method in the receiver. Sometimes the behaviour must also be determined by the type of the parameter.

In some languages that encourage the use of a switch/case construct, one solution would be for the method to switch on the type of the parameter and to execute different code as a result. However, in Smalltalk no switch statement is provided and nested ifTrue:ifFalse: messages are frowned upon. If a new class of parameter object was added, then the switch code would also have to be modified to cater for the new class (a maintenance issue).

Solution

In Smalltalk a better solution is to make use of the polymorphic nature of the language and to use a technique known as double dispatching. This involves adding a new method (we'll call this a secondary method) to the classes of all the potential parameter objects and then calling this from the original method with the receiver as a parameter. The selector of the secondary method should be constructed from the primary method selector followed by the class name of the original receiver.

Known Uses

The Integer class hierarchy uses double dispatch to implement some of the arithmetic functions, including #+ (plus).

#+ is defined by Integer as follows:

Integer>>+ aNumber
	"Answer a Number which is the sum of the receiver and aNumber"

	^aNumber addToInteger: self

Inside this method, we know that aNumber is being added to the receiver (which is an Integer). To avoid writing code to switch on the type of the parameter aNumber, we can simply ask aNumber to perform the calculation for us.

There is a default implementation of #addToInteger in Number

ArithmeticValue>>addToInteger: anInteger
	"Private - Answer the result of adding the receiver to the known integer, anInteger, by 
	coercing the less general of it and the receiver. Overridden by subclasses which 
	can implement more efficiently."
	^anInteger retry: #+ coercing: self

Each subclass of Integer which requires specialist addition processing implements its own #addToInteger. For example the Fraction class knows how to add an integer to itself:

addToInteger: anInteger 
	"Private - Add the known integer, anInteger, to the receiver. There is no need
	to rationalise the result."

	^Fraction
		numerator: anInteger * denominator + numerator
		denominator: denominator 

Related Patterns