Class::Multimethods - Multiple Dispatch and Subroutine Overloading in Perl

Damian Conway

School of Computer Science and Software Engineering
Monash University
Clayton 3168, Australia

mailto:damian@csse.monash.edu.au
http://www.csse.monash.edu.au/~damian
phone: +61-3-9905-5184
fax: +61-3-9905-4146

Extended Abstract

In object-oriented Perl, the selection of which subroutine to call in response to a method invocation is always determined by the class of the original invoking object (i.e. according to the class of the first argument). For most applications, the ability to select behaviour based on the type of a single argument is sufficient. However, some applications need to select the most applicable polymorphic method on the basis of more than one argument. This requirement is known as multiple dispatch.

Generally speaking, multiple dispatch is needed whenever two or more objects belonging to different class hierarchies are going to interact, and it's necessary to do different things depending on the combination of actual types of those objects. Typical candidates are graphical user interfaces, image processing libraries, mixed-precision numerical computation systems, and most types of simulations.

It's possible to build "hand-crafted" multiply-dispatched methods that look at the types of each of their arguments and react accordingly. Two such approaches are described in [1,2]. The problem with these approaches is that they are complicated to construct and even harder to debug. And because every "hand-crafted" method is structurally similar, they're tedious to code and maintain.

The Class:Multimethod module[3] exports a subroutine (multimethod) that can be used to declare sets of subroutines that are multiply dispatched. Each such subroutine is known as a variant, and collectively they are known as a multimethod.

When a multimethod is called, the multiple dispatch mechanism installed by Class::Multimethods looks at the classes or types of each argument (by calling ref on each) and determines the "closest" matching variant of the multimethod.

The result is something akin to C++'s function overloading but more sophisticated, since multimethods take the inheritance relationships of each argument into account. Another way of thinking of the mechanism is that it performs polymorphic dispatch on every argument of a method, not just on the first.

Of course, the usefulness of this new dispatch mechanism depends on how intelligently Class::Multimethods decides which variant of a multimethod is "nearest" to a given set of arguments. That decision process is called dispatch resolution, and Class::Multimethods does it by simultaneously performing a breadth-first traversal of each argument's class hierarchy, searching for the first combination of ancestral parameter types that are individually compatible accept the actual arguments.

This means that the cost of a single call to a multimethod is greater than the cost of a call to a normal Perl method. Of course a multimethod call is also more powerful, and if the normal method has to perform additional tests to indentify its other arguments and branch to an appropriate handler, then multimethods are no more expensive.

Multimethods don't belong to any particular package (not even the one in which they were defined). Instead, they occupy an entirely distinct namespace where every variant is visible to every multimethod call. Class::Multimethods therefore also supplies a mechanism for importing a multimethod into a regular Perl namespace (i.e. into a package).

Unlike normal Perl methods, multimethods may be called either through the $obj->method(@args) notation, or as regular subroutines (i.e. method($obj,@args)), with no difference in their dispatch behaviour. This means that multimethods can also act as a subroutine overloading mechanism. They may also be specified with in-built reference types as parameters (using the standard identifiers ARRAY, HASH, CODE, etc.), as well as string and numeric scalars (using special parameter pseudo-types).

Multimethod dispatch can become quite complicated and unpredictable if many variants are available or if the parameter classes' hierarchies are complex. To assist in debugging such cases Class::Multimethods provides a special subroutine that takes the name of a multimethod and generates a report listing the dispatch behaviour of that multimethod under all feasible combinations of its various possible arguments.
 

Detailed Outline

  1. What is multiple dispatch?
  2. The Class::Multimethods module
  3. Defining multimethods
  4. Finding the "nearest" multimethod
  5. Declaring multimethods
  6. Subroutine overloading
  7. Non-class types as parameters
  8. Recursive multiple dispatch
  9. Resolving ambiguities and non-dispatchable calls
  10. Debugging a multimethod
  11. Conclusion
  12. References

Full Paper

The full paper is available in both HTML and PostScript.
 

Source Code

The Class::Multimethods module is available from the CPAN.

References

  1. Conway, D., Object Oriented Perl, Chapter 13, Manning Publications, 1999.
  2. Conway, D., Multiple Dispatch in Perl,The Perl Journal (to appear).
  3. http://www.cs.monash.edu.au/~damian/CPAN/Class-Multimethods.tar.gz