Agile Zone is brought to you in partnership with:

I am a programmer and architect (the kind that writes code) with a focus on testing and open source; I maintain the PHPUnit_Selenium project. I believe programming is one of the hardest and most beautiful jobs in the world. Giorgio is a DZone MVB and is not an employee of DZone and has posted 638 posts at DZone. You can read more from them at their website. View Full User Profile

Double Dispatch: the next best thing with respect to Dependency Injection

12.07.2010
| 8952 views |
  • submit to reddit

Object-oriented languages, like C++, Java and PHP, implement what is called single dispatch: when you have an object in a variable and you call a method on this variable, the message is dispatched to the right class at runtime, even if when you write the code you do not want to tie the call to a particular implementation. Polymorphism is an example of this mechanism in action.

Double Dispatch meaning

Double Dispatch is a simple idea: change behavior also depending on the caller's class, and not only on the called class. Why we would want to do that?

Wikipedia makes the example of adaptive collision algorithms, that calculate the result of the collision between two objects. The laws of physics prescribe that the collision depend on the characteristics of the two objects, so when we collide an Asteroid with a Spaceship we may want to reach a different outcome when the Asteroid is an instance of the subclass GiantAsteroid, or the Spaceship is an instance of the subclass GiantSpaceship.

With a more mundane example, we want something like this:

class NotNullValidator
{
public function isValid(ValidableEntity $entity)
{
return $entity->isValid();
}
}
$validator = new NotNullValidator();
$entity = new User();
var_dump($validator->isValid());
to produce this output:
User-specific code can be inserted here.
NotNullValidator-specific code can be inserted here.

With the initial design, we can only achieve this by adding code to the NotNullValidator class. The point however is instead: how can we make the User::isValid() method, which is resolved by the language to be used when ValidableEntity $entity happens to be an User, to recognize that it was called by NotNullValidator and not from something else? We want to encapsulate this "choice of caller" into the User class, for example because it needs access to the User's private fields, a trait which defines a line of code as belonging to the User class and not to anyone else.

Double Dispatch implementation

I anticipate that the way to go is to transform the caller also in a parameter. Even if the language used does not support parameters overloading to support variations on the caller class, we can easily forward the call to the parameter and use simple dispatch again.

Even in the languages where overloading is available, like C, it is usually not done dinamically (like for virtual methods) and the method to call is selected at compile time, basing on the reference variable. This means that in C the User object, pointed by an handler of type ValidableEntity, will only select the method which takes ValidableEntity as an argument for dispatch, even if multiple overloaded version of the method are available.

Mormally, OO languages only support single dispatch: the actual method called varies on the class of the called object, but has no way to distinguish between the calling ones. As simple, I mean different from an hack that involves the stack trace. Therefore, Double Dispatch is implemented via the Visitor pattern for the majority of object-oriented languages.

Practical usage

When Double Dispatch comes handy? It is a common solution for providing collaborators to Entity classes (e.g. User, Post, Group, Article...) of a Domain Model.
Usually we cannot inject collaborators in such classes, since the ORM won't now how to reconstitute the objects unless you configure some listener that is passed each reconstituted object. This is true in the case of Active Records (even if the Entity term is wasted in that case) and also if the ORM is a Data Mapper. The User class of the example can implement Double Dispatch instead: in this case, one dispatch is done over the $user variable and the other one over the collaborator, which is passed as a parameter. The collaborator does not need to also be the caller, only to be passed to the Entity in the signature of the method where it is needed.

<?php
/**
* An Element in the Visitor pattern implementation.
*/
interface ValidableEntity
{
public function isValid(Validator $validator);
}

class User implements ValidableEntity
{
private $name = 'Giorgio';

public function isValid(Validator $validator)
{
echo "User-specific code can be inserted here.\n";
return $validator->validate(array('name' => $this->name));
}
}

/**
* Validators are Visitors, but implemented in the push style:
* the ValidableEntity only passes the necessary values to the Visitor.
*/
interface Validator
{
public function validate($values);
}

class NotNullValidator implements Validator
{
public function validate($values)
{
echo "NotNullValidator-specific code can be inserted here.\n";
foreach ($values as $fieldName => $eachValue) {
if ($eachValue === null) {
return false;
}
}
return true;
}

/**
* This is the entry point: we implement Double Dispatch by passing the caller
* object to the called one, so that the called can call a method on the original
* caller and take advatange of the method resolution supported by the language.
* The sum of two simple dispatches is a Double Dispatch. In the pattern's
* terminology, the Visitor is also the Client.
*/
public function isValid(ValidableEntity $entity)
{
return $entity->isValid($this);
}
}

$user = new User();
$validator = new NotNullValidator(/* collaborators can be injected here */);
var_dump($validator->isValid($user));

The advantages

With Double Dispatch, of course we do not need to inject other objects in Entities, which I came to think is not a Domain-Driven Design practice. Injecting would also be not very appropriate, since this kind of dependencies is used only in one or two methods (as in the example, for validation related ones).

The Api of the Entity becomes complete: everything you need is present as a method on the Entity, which is therefore not so anemic as in the case of external objects handling its logic. In our original example, the validation methods are present on the Entity and not on the Validator: this design is positively different from a Validator having to access the User's data by reflection or some privileged public method.

The Entity can pass to the Visitor only the necessary private data, so that its encapsulation is not violated. In the example, User passed the values of its private fields, which shouldn't be exposed anywhere. Moreover, the dependency on the collaborator is clearly visible: it's in the method signature. This is a step forward from the inserting a new Collaborator() into the Entity itself.

Conclusion

The only downside is that the caller of the Entity Api must be injected with the collaborator to be able to pass it to the Entity itself. Still, we cannot totally hide a dependency: it has to be injected somewhere, and not having an available Entity constructor, Double Dispatch gives us a standard solution as the next best thing with respect to DI.

References:

http://en.wikipedia.org/wiki/Double_dispatch

http://misko.hevery.com/2009/07/31/how-to-think-about-oo/

http://c2.com/cgi/wiki?DoubleDispatch

Published at DZone with permission of Giorgio Sironi, author and DZone MVB.

(Note: Opinions expressed in this article and its replies are the opinions of their respective authors and not those of DZone, Inc.)