fbpx
Wikipedia

Multiple dispatch

Multiple dispatch or multimethods is a feature of some programming languages in which a function or method can be dynamically dispatched based on the run-time (dynamic) type or, in the more general case, some other attribute of more than one of its arguments.[1] This is a generalization of single-dispatch polymorphism where a function or method call is dynamically dispatched based on the derived type of the object on which the method has been called. Multiple dispatch routes the dynamic dispatch to the implementing function or method using the combined characteristics of one or more arguments.

Understanding dispatch edit

Developers of computer software typically organize source code into named blocks variously called subroutines, procedures, subprograms, functions, or methods. The code in the function is executed by calling it – executing a piece of code that references its name. This transfers control temporarily to the called function; when the function's execution has completed, control is typically transferred back to the instruction in the caller that follows the reference.

Function names are usually selected so as to be descriptive of the function's purpose. It is sometimes desirable to give several functions the same name, often because they perform conceptually similar tasks, but operate on different types of input data. In such cases, the name reference at the function call site is not sufficient for identifying the block of code to be executed. Instead, the number and type of the arguments to the function call are also used to select among several function implementations.

In more conventional, i.e., single-dispatch object-oriented programming languages, when invoking a method (sending a message in Smalltalk, calling a member function in C++), one of its arguments is treated specially and used to determine which of the (potentially many) classes of methods of that name is to be applied. In many languages, the special argument is indicated syntactically; for example, a number of programming languages put the special argument before a dot in making a method call: special.method(other, arguments, here), so that lion.sound() would produce a roar, whereas sparrow.sound() would produce a chirp.

In contrast, in languages with multiple dispatch, the selected method is simply the one whose arguments match the number and type of the function call. There is no special argument that owns the function/method carried out in a particular call.

The Common Lisp Object System (CLOS) is an early and well-known example of multiple dispatch. Another notable example of the use of multiple dispatch is the Julia programming language.

Multiple dispatch should be distinguished from function overloading, in which static typing information, such as a term's declared or inferred type (or base type in a language with subtyping) is used to determine which of several possibilities will be used at a given call site, and that determination is made at compile or link time (or some other time before program execution starts) and is thereafter invariant for a given deployment or run of the program. Many languages such as C++ offer robust function overloading but do not offer dynamic multiple dispatch (C++ only permits dynamic single dispatch through use of virtual functions).

Data types edit

When working with languages that can discriminate data types at compile time, selecting among the alternatives can occur then. The act of creating such alternative functions for compile time selection is usually referred to as overloading a function.

In programming languages that defer data type identification until run time (i.e., late binding), selection among alternative functions must occur then, based on the dynamically determined types of function arguments. Functions whose alternative implementations are selected in this manner are referred to most generally as multimethods.

There is some run-time cost associated with dynamically dispatching function calls. In some languages,[citation needed] the distinction between overloading and multimethods can be blurred, with the compiler determining whether compile time selection can be applied to a given function call, or whether slower run time dispatch is needed.

Issues edit

There are several known issues with dynamic-dispatch, both single and multiple. While many of these issues are solved for single-dispatch, which has been a standard feature in object-oriented programming languages for decades, these issues become more complicated in the multiple-dispatch case.

Expressiveness and modularity edit

In most popular programming languages, source code is delivered and deployed in granules of functionality which we will here call packages; actual terminology for this concept varies between language. Each package may contain multiple type, value, and function definitions, packages are often compiled separately in languages with a compilation step, and a non-cyclical dependency relationship may exist. A complete program is a set of packages, with a main package which may depend on several other packages, and the whole program consisting of the transitive closure of the dependency relationship.

The so-called expression problem relates to the ability for code in a depending package to extend behaviors (functions or datatypes) defined in a base package from within an including package, without modifying the source to the base package. Traditional single-dispatch OO languages make it trivial to add new datatypes but not new functions; traditional functional languages tend to have the opposite effect, and multiple dispatch, if implemented correctly, allows both. It is desirable for an implementation of multiple dispatch to have the following properties:

  • It is possible to define different "cases" of a multi-method from within different packages without modifying the source of a base package.
  • Inclusion of another package in the program should not change the behavior of a given multi-method call, when the call does not use any datatypes defined in the package.
  • Conversely, if a datatype is defined in a given package, and a multi-method extension using that type is also defined in the same package, and a value of that type is passed (through a base type reference or into a generic function) into another package with no dependency on that package, and then the multi-method is invoked with that value as an argument, the multi-method case defined in the package which includes the type should be employed. To put it another way—within a given program, the same multi-method invoked with the same set of arguments should resolve to the same implementation, regardless of the location of the call site, and whether or not a given definition is "in scope" or "visible" at the point of the method call.

Ambiguity edit

It is generally desirable that for any given invocation of a multi-method, there be at most one "best" candidate among implementation cases of the multi-method, and/or that if there is not, that this be resolved in a predictable and deterministic fashion, including failure. Non-deterministic behavior is undesirable. Assuming a set of types with a non-circular subtyping relationship, one can define that one implementation of a multi-method is "better" (more specific) if all dynamically-dispatched arguments in the first are subtypes of all dynamically-dispatched arguments specified in the second, and at least one is a strict subtype. With single dispatch and in the absence of multiple inheritance, this condition is trivially satisfied, but with multiple dispatch, it is possible for two or more candidates to satisfy a given actual argument list, but neither is more specific than the other (one dynamic argument being the subtype in one case, another being the subtype in the other case). This particularly can happen if two different packages, neither depending on the other, both extend some multi-method with implementations concerning each package's types, and then a third package that includes both (possibly indirectly) then invokes the multi-method using arguments from both packages.

Possible resolutions include:

  • Treating any ambiguous calls as an error. This might be caught at compile time (or otherwise before deployment), but might not be detected until runtime and produce a runtime error.
  • Ordering the arguments, so e.g. the case with the most specific first argument is selected, and subsequent arguments are not considered for ambiguity resolution unless the first argument is insufficient to resolve the issue.
  • Construction of other rules for resolving an ambiguity in one direction or another. Sometimes, such rules might be arbitrary and surprising. In the rules for static overload resolution in C++, for instance, a type which matches exactly is understandably considered a better match than a type which matches through a base type reference or a generic (template) parameter. However, if the only possible matches are either through a base type or a generic parameter, the generic parameter is preferred over the base type, a rule that sometimes produces surprising behavior.

Efficiency edit

Efficient implementation of single-dispatch, including in programming languages that are separately compiled to object code and linked with a low-level (not-language-aware) linker, including dynamically at program load/start time or even under the direction of the application code, are well known. The "vtable" method developed in C++ and other early OO languages (where each class has an array of function pointers corresponding to that class's virtual functions) is nearly as fast as a static method call, requiring O(1) overhead and only one additional memory lookup even in the un-optimized case. However, the vtable method uses the function name and not the argument type as its lookup key, and does not scale to the multiple dispatch case. (It also depends on the object-oriented paradigm of methods being features of classes, not standalone entities independent of any particular datatype).

Efficient implementation of multiple-dispatch remains an ongoing research problem.

Use in practice edit

To estimate how often multiple dispatch is used in practice, Muschevici et al.[2] studied programs that use dynamic dispatch. They analyzed nine applications, mostly compilers, written in six different languages: Common Lisp Object System, Dylan, Cecil, MultiJava, Diesel, and Nice. Their results show that 13–32% of generic functions use the dynamic type of one argument, while 2.7–6.5% of them use the dynamic type of multiple arguments. The remaining 65–93% of generic functions have one concrete method (overrider), and thus are not considered to use the dynamic types of their arguments. Further, the study reports that 2–20% of generic functions had two and 3–6% had three concrete function implementations. The numbers decrease rapidly for functions with more concrete overriders.

Multiple dispatch is used much more heavily in Julia, where multiple dispatch was a central design concept from the origin of the language: collecting the same statistics as Muschevici on the average number of methods per generic function, it was found that the Julia standard library uses more than double the amount of overloading than in the other languages analyzed by Muschevici, and more than 10 times in the case of binary operators.[3]

The data from these papers is summarized in the following table, where the dispatch ratio DR is the average number of methods per generic function; the choice ratio CR is the mean of the square of the number of methods (to better measure the frequency of functions with a large number of methods);[2][3] and the degree of specialization DoS is the average number of type-specialized arguments per method (i.e., the number of arguments that are dispatched on):

Language Average # methods (DR) Choice ratio (CR) Degree of specialization (DoS)
Cecil[2] 2.33 63.30 1.06
Common Lisp (CMU)[2] 2.03 6.34 1.17
Common Lisp (McCLIM)[2] 2.32 15.43 1.17
Common Lisp (Steel Bank)[2] 2.37 26.57 1.11
Diesel[2] 2.07 31.65 0.71
Dylan (Gwydion)[2] 1.74 18.27 2.14
Dylan (OpenDylan)[2] 2.51 43.84 1.23
Julia[3] 5.86 51.44 1.54
Julia (operators only)[3] 28.13 78.06 2.01
MultiJava[2] 1.50 8.92 1.02
Nice[2] 1.36 3.46 0.33

Theory edit

The theory of multiple dispatching languages was first developed by Castagna et al., by defining a model for overloaded functions with late binding.[4][5] It yielded the first formalization of the problem of covariance and contravariance of object-oriented languages[6] and a solution to the problem of binary methods.[7]

Examples edit

Distinguishing multiple and single dispatch may be made clearer by an example. Imagine a game that has, among its (user-visible) objects, spaceships and asteroids. When two objects collide, the program may need to do different things according to what has just hit what.

Languages with built-in multiple dispatch edit

C# edit

C# introduced support for dynamic multimethods in version 4[8] (April 2010) using the 'dynamic' keyword. The following example demonstrates multimethods. Like many other statically-typed languages, C# also supports static method overloading.[9] Microsoft expects that developers will choose static typing over dynamic typing in most scenarios.[10] The 'dynamic' keyword supports interoperability with COM objects and dynamically-typed .NET languages.

 

The example below uses features introduced in C# 9 and C# 10.

using static ColliderLibrary; Console.WriteLine(Collide(new Asteroid(101), new Spaceship(300))); Console.WriteLine(Collide(new Asteroid(10), new Spaceship(10))); Console.WriteLine(Collide(new Spaceship(101), new Spaceship(10))); string Collide(SpaceObject x, SpaceObject y) =>  x.Size > 100 && y.Size > 100  ? "Big boom!"  : CollideWith(x as dynamic, y as dynamic); // Dynamic dispatch to CollideWith method class ColliderLibrary {  public static string CollideWith(Asteroid x, Asteroid y) => "a/a";  public static string CollideWith(Asteroid x, Spaceship y) => "a/s";  public static string CollideWith(Spaceship x, Asteroid y) => "s/a";  public static string CollideWith(Spaceship x, Spaceship y) => "s/s"; } abstract record SpaceObject(int Size); record Asteroid(int Size) : SpaceObject(Size); record Spaceship(int Size) : SpaceObject(Size); 

Output:

Big boom! a/s s/s 

Groovy edit

Groovy is a general purpose Java compatible/interusable JVM language, which, contrary to Java, uses late binding / multiple dispatch.[11]

/*  Groovy implementation of C# example above  Late binding works the same when using non-static methods or compiling class/methods statically  (@CompileStatic annotation) */ class Program {  static void main(String[] args) {  println Collider.collide(new Asteroid(101), new Spaceship(300))  println Collider.collide(new Asteroid(10), new Spaceship(10))  println Collider.collide(new Spaceship(101), new Spaceship(10))  } } class Collider {  static String collide(SpaceObject x, SpaceObject y) {  (x.size > 100 && y.size > 100) ? "big-boom" : collideWith(x, y) // Dynamic dispatch to collideWith method  }  private static String collideWith(Asteroid x, Asteroid y) { "a/a" }  private static String collideWith(Asteroid x, Spaceship y) { "a/s" }  private static String collideWith(Spaceship x, Asteroid y) { "s/a" }  private static String collideWith(Spaceship x, Spaceship y) { "s/s"} } class SpaceObject {  int size  SpaceObject(int size) { this.size = size } } @InheritConstructors class Asteroid extends SpaceObject {} @InheritConstructors class Spaceship extends SpaceObject {} 

Common Lisp edit

In a language with multiple dispatch, such as Common Lisp, it might look more like this (Common Lisp example shown):

(defmethod collide-with ((x asteroid) (y asteroid))  ;; deal with asteroid hitting asteroid  ) (defmethod collide-with ((x asteroid) (y spaceship))  ;; deal with asteroid hitting spaceship  ) (defmethod collide-with ((x spaceship) (y asteroid))  ;; deal with spaceship hitting asteroid  ) (defmethod collide-with ((x spaceship) (y spaceship))  ;; deal with spaceship hitting spaceship  ) 

and similarly for the other methods. Explicit testing and "dynamic casting" are not used.

In the presence of multiple dispatch, the traditional idea of methods as being defined in classes and contained in objects becomes less appealing—each collide-with method above is attached to two different classes, not one. Hence, the special syntax for method invocation generally disappears, so that method invocation looks exactly like ordinary function invocation, and methods are grouped not in classes but in generic functions.

Julia edit

Julia has built-in multiple dispatch, and it is central to the language design.[3] The Julia version of the example above might look like:

abstract type SpaceObject end struct Asteroid <: SpaceObject  size::Int  end struct Spaceship <: SpaceObject  size::Int  end collide_with(::Asteroid, ::Spaceship) = "a/s" collide_with(::Spaceship, ::Asteroid) = "s/a" collide_with(::Spaceship, ::Spaceship) = "s/s" collide_with(::Asteroid, ::Asteroid) = "a/a" collide(x::SpaceObject, y::SpaceObject) = (x.size > 100 && y.size > 100) ? "Big boom!" : collide_with(x, y) 

Output:

julia> collide(Asteroid(101), Spaceship(300)) "Big boom!" julia> collide(Asteroid(10), Spaceship(10)) "a/s" julia> collide(Spaceship(101), Spaceship(10)) "s/s" 

Raku edit

Raku, like Perl, uses proven ideas from other languages, and type systems have shown themselves to offer compelling advantages in compiler-side code analysis and powerful user-side semantics via multiple dispatch.

It has both multimethods, and multisubs. Since most operators are subroutines, it also has multiple dispatched operators.

Along with the usual type constraints, it also has where constraints that allow making very specialized subroutines.

subset Mass of Real where 0 ^..^ Inf; role Stellar-Object { has Mass $.mass is required; method name () returns Str {...}; } class Asteroid does Stellar-Object { method name () { 'an asteroid' } } class Spaceship does Stellar-Object { has Str $.name = 'some unnamed spaceship'; } my Str @destroyed = < obliterated destroyed mangled >; my Str @damaged = « damaged 'collided with' 'was damaged by' »; # We add multi candidates to the numeric comparison operators because we are comparing them numerically, # but makes no sense to have the objects coerce to a Numeric type. # ( If they did coerce we wouldn't necessarily need to add these operators. ) # We could have also defined entirely new operators this same way. multi sub infix:« <=> » ( Stellar-Object:D $a, Stellar-Object:D $b ) { $a.mass <=> $b.mass } multi sub infix:« < » ( Stellar-Object:D $a, Stellar-Object:D $b ) { $a.mass < $b.mass } multi sub infix:« > » ( Stellar-Object:D $a, Stellar-Object:D $b ) { $a.mass > $b.mass } multi sub infix:« == » ( Stellar-Object:D $a, Stellar-Object:D $b ) { $a.mass == $b.mass } # Define a new multi dispatcher, and add some type constraints to the parameters. # If we didn't define it we would have gotten a generic one that didn't have constraints. proto sub collide ( Stellar-Object:D $, Stellar-Object:D $ ) {*} # No need to repeat the types here since they are the same as the prototype. # The 'where' constraint technically only applies to $b not the whole signature. # Note that the 'where' constraint uses the `<` operator candidate we added earlier. multi sub collide ( $a, $b where $a < $b ) { say "$a.name() was @destroyed.pick() by $b.name()"; } multi sub collide ( $a, $b where $a > $b ) { # redispatch to the previous candidate with the arguments swapped samewith $b, $a; } # This has to be after the first two because the other ones # have 'where' constraints, which get checked in the # order the subs were written. ( This one would always match. ) multi sub collide ( $a, $b ) { # randomize the order my ($n1, $n2) = ( $a.name, $b.name ).pick(*); say "$n1 @damaged.pick() $n2"; } # The following two candidates can be anywhere after the proto, # because they have more specialized types than the preceding three. # If the ships have unequal mass one of the first two candidates gets called instead. multi sub collide ( Spaceship $a, Spaceship $b where $a == $b ){ my ($n1, $n2) = ( $a.name, $b.name ).pick(*); say "$n1 collided with $n2, and both ships were ", ( @destroyed.pick, 'left damaged' ).pick; } # You can unpack the attributes into variables within the signature. # You could even have a constraint on them `(:mass($a) where 10)`. multi sub collide ( Asteroid $ (:mass($a)), Asteroid $ (:mass($b)) ){ say "two asteroids collided and combined into one larger asteroid of mass { $a + $b }"; } my Spaceship $Enterprise .= new(:mass(1),:name('The Enterprise')); collide Asteroid.new(:mass(.1)), $Enterprise; collide $Enterprise, Spaceship.new(:mass(.1)); collide $Enterprise, Asteroid.new(:mass(1)); collide $Enterprise, Spaceship.new(:mass(1)); collide Asteroid.new(:mass(10)), Asteroid.new(:mass(5)); 

Extending languages with multiple-dispatch libraries edit

JavaScript edit

In languages that do not support multiple dispatch at the language definition or syntactic level, it is often possible to add multiple dispatch using a library extension. JavaScript and TypeScript do not support multimethods at the syntax level, but it is possible to add multiple dispatch via a library. For example, the multimethod package[12] provides an implementation of multiple dispatch, generic functions.

Dynamically-typed version in JavaScript:

import { multi, method } from '@arrows/multimethod' class Asteroid {} class Spaceship {} const collideWith = multi(  method([Asteroid, Asteroid], (x, y) => {  // deal with asteroid hitting asteroid  }),  method([Asteroid, Spaceship], (x, y) => {  // deal with asteroid hitting spaceship  }),  method([Spaceship, Asteroid], (x, y) => {  // deal with spaceship hitting asteroid  }),  method([Spaceship, Spaceship], (x, y) => {  // deal with spaceship hitting spaceship  }), ) 

Statically-typed version in TypeScript:

import { multi, method, Multi } from '@arrows/multimethod' class Asteroid {} class Spaceship {} type CollideWith = Multi & {  (x: Asteroid, y: Asteroid): void  (x: Asteroid, y: Spaceship): void  (x: Spaceship, y: Asteroid): void  (x: Spaceship, y: Spaceship): void } const collideWith: CollideWith = multi(  method([Asteroid, Asteroid], (x, y) => {  // deal with asteroid hitting asteroid  }),  method([Asteroid, Spaceship], (x, y) => {  // deal with asteroid hitting spaceship  }),  method([Spaceship, Asteroid], (x, y) => {  // deal with spaceship hitting asteroid  }),  method([Spaceship, Spaceship], (x, y) => {  // deal with spaceship hitting spaceship  }), ) 

Python edit

Multiple dispatch can be added to Python using a library extension. For example, using the module multimethod.py[13] and also with the module multimethods.py[14] which provides CLOS-style multimethods for Python without changing the underlying syntax or keywords of the language.

from multimethods import Dispatch from game_objects import Asteroid, Spaceship from game_behaviors import as_func, ss_func, sa_func collide = Dispatch() collide.add_rule((Asteroid, Spaceship), as_func) collide.add_rule((Spaceship, Spaceship), ss_func) collide.add_rule((Spaceship, Asteroid), sa_func) def aa_func(a, b):  """Behavior when asteroid hits asteroid.""" # ...define new behavior... collide.add_rule((Asteroid, Asteroid), aa_func) 
# ...later... collide(thing1, thing2) 

Functionally, this is very similar to the CLOS example, but the syntax is conventional Python.

Using Python 2.4 decorators, Guido van Rossum produced a sample implementation of multimethods[15] with a simplified syntax:

@multimethod(Asteroid, Asteroid) def collide(a, b):  """Behavior when asteroid hits a asteroid.""" # ...define new behavior... @multimethod(Asteroid, Spaceship) def collide(a, b):  """Behavior when asteroid hits a spaceship.""" # ...define new behavior... # ... define other multimethod rules ... 

and then it goes on to define the multimethod decorator.

The PEAK-Rules package provides multiple dispatch with a syntax similar to the above example.[16] It was later replaced by PyProtocols.[17]

The Reg library also supports multiple and predicate dispatch.[18]

With the introduction of type hints, multiple dispatch is possible with even simpler syntax. For example, using plum-dispatch,

from plum import dispatch @dispatch def collide(a: Asteroid, b: Asteroid):  """Behavior when asteroid hits a asteroid.""" # ...define new behavior... @dispatch def collide(a: Asteroid, b: Spaceship):  """Behavior when asteroid hits a spaceship.""" # ...define new behavior... # ...define further rules... 

Emulating multiple dispatch edit

C edit

C does not have dynamic dispatch, so it must be implemented manually in some form. Often an enum is used to identify the subtype of an object. Dynamic dispatch can be done by looking up this value in a function pointer branch table. Here is a simple example in C:

typedef void (*CollisionCase)(void); void collision_AA(void) { /* handle Asteroid-Asteroid collision */ }; void collision_AS(void) { /* handle Asteroid-Spaceship collision */ }; void collision_SA(void) { /* handle Spaceship-Asteroid collision */ }; void collision_SS(void) { /* handle Spaceship-Spaceship collision*/ }; typedef enum {  THING_ASTEROID = 0,  THING_SPACESHIP,  THING_COUNT /* not a type of thing itself, instead used to find number of things */ } Thing; CollisionCase collisionCases[THING_COUNT][THING_COUNT] = {  {&collision_AA, &collision_AS},  {&collision_SA, &collision_SS} }; void collide(Thing a, Thing b) {  (*collisionCases[a][b])(); } int main(void) {  collide(THING_SPACESHIP, THING_ASTEROID); } 

With the C Object System library,[19] C does support dynamic dispatch similar to CLOS. It is fully extensible and does not need any manual handling of the methods. Dynamic message (methods) are dispatched by the dispatcher of COS, which is faster than Objective-C. Here is an example in COS:

#include <stdio.h> #include <cos/Object.h> #include <cos/gen/object.h> // classes defclass (Asteroid) // data members endclass defclass (Spaceship) // data members endclass // generics defgeneric (_Bool, collide_with, _1, _2); // multimethods defmethod (_Bool, collide_with, Asteroid, Asteroid)  // deal with asteroid hitting asteroid endmethod defmethod (_Bool, collide_with, Asteroid, Spaceship)  // deal with asteroid hitting spaceship endmethod defmethod (_Bool, collide_with, Spaceship, Asteroid)  // deal with spaceship hitting asteroid endmethod defmethod (_Bool, collide_with, Spaceship, Spaceship)  // deal with spaceship hitting spaceship endmethod // example of use int main(void) {  OBJ a = gnew(Asteroid);  OBJ s = gnew(Spaceship);  printf("<a,a> = %d\n", collide_with(a, a));  printf("<a,s> = %d\n", collide_with(a, s));  printf("<s,a> = %d\n", collide_with(s, a));  printf("<s,s> = %d\n", collide_with(s, s));  grelease(a);  grelease(s); } 

C++ edit

As of 2021, C++ natively supports only single dispatch, though adding multi-methods (multiple dispatch) was proposed by Bjarne Stroustrup (and collaborators) in 2007.[20] The methods of working around this limit are analogous: use either the visitor pattern, dynamic cast or a library:

 // Example using run time type comparison via dynamic_cast  struct Thing {  virtual void collideWith(Thing& other) = 0;  };  struct Asteroid : Thing {  void collideWith(Thing& other) {  // dynamic_cast to a pointer type returns NULL if the cast fails  // (dynamic_cast to a reference type would throw an exception on failure)  if (auto asteroid = dynamic_cast<Asteroid*>(&other)) {  // handle Asteroid-Asteroid collision  } else if (auto spaceship = dynamic_cast<Spaceship*>(&other)) {  // handle Asteroid-Spaceship collision  } else {  // default collision handling here  }  }  };  struct Spaceship : Thing {  void collideWith(Thing& other) {  if (auto asteroid = dynamic_cast<Asteroid*>(&other)) {  // handle Spaceship-Asteroid collision  } else if (auto spaceship = dynamic_cast<Spaceship*>(&other)) {  // handle Spaceship-Spaceship collision  } else {  // default collision handling here  }  }  }; 

or pointer-to-method lookup table:

#include <cstdint> #include <typeinfo> #include <unordered_map> class Thing {  protected:  Thing(std::uint32_t cid) : tid(cid) {}  const std::uint32_t tid; // type id  typedef void (Thing::*CollisionHandler)(Thing& other);  typedef std::unordered_map<std::uint64_t, CollisionHandler> CollisionHandlerMap;  static void addHandler(std::uint32_t id1, std::uint32_t id2, CollisionHandler handler) {  collisionCases.insert(CollisionHandlerMap::value_type(key(id1, id2), handler));  }  static std::uint64_t key(std::uint32_t id1, std::uint32_t id2) {  return std::uint64_t(id1) << 32 | id2;  }  static CollisionHandlerMap collisionCases;  public:  void collideWith(Thing& other) {  auto handler = collisionCases.find(key(tid, other.tid));  if (handler != collisionCases.end()) {  (this->*handler->second)(other); // pointer-to-method call  } else {  // default collision handling  }  } }; class Asteroid: public Thing {  void asteroid_collision(Thing& other) { /*handle Asteroid-Asteroid collision*/ }  void spaceship_collision(Thing& other) { /*handle Asteroid-Spaceship collision*/}  public:  Asteroid(): Thing(cid) {}  static void initCases();  static const std::uint32_t cid; }; class Spaceship: public Thing {  void asteroid_collision(Thing& other) { /*handle Spaceship-Asteroid collision*/}  void spaceship_collision(Thing& other) { /*handle Spaceship-Spaceship collision*/}  public:  Spaceship(): Thing(cid) {}  static void initCases();  static const std::uint32_t cid; // class id }; Thing::CollisionHandlerMap Thing::collisionCases; const std::uint32_t Asteroid::cid = typeid(Asteroid).hash_code(); const std::uint32_t Spaceship::cid = typeid(Spaceship).hash_code(); void Asteroid::initCases() {  addHandler(cid, cid, CollisionHandler(&Asteroid::asteroid_collision));  addHandler(cid, Spaceship::cid, CollisionHandler(&Asteroid::spaceship_collision)); } void Spaceship::initCases() {  addHandler(cid, Asteroid::cid, CollisionHandler(&Spaceship::asteroid_collision));  addHandler(cid, cid, CollisionHandler(&Spaceship::spaceship_collision)); } int main() {  Asteroid::initCases();  Spaceship::initCases();  Asteroid a1, a2;  Spaceship s1, s2;  a1.collideWith(a2);  a1.collideWith(s1);  s1.collideWith(s2);  s1.collideWith(a1); } 

The YOMM2 library[21] provides a fast, orthogonal implementation of open multimethods.

The syntax for declaring open methods is inspired by a proposal for a native C++ implementation. The library requires that the user registers all the classes used as virtual arguments (and their sub-classes), but does not require any modifications to existing code. Methods are implemented as ordinary inline C++ functions; they can be overloaded and they can be passed by pointer. There is no limit on the number of virtual arguments, and they can be arbitrarily mixed with non-virtual arguments.

The library uses a combination of techniques (compressed dispatch tables, collision free integer hash table) to implement method calls in constant time, while mitigating memory usage. Dispatching a call to an open method with a single virtual argument takes only 15–30% more time than calling an ordinary virtual member function, when a modern optimizing compiler is used.

The Asteroids example can be implemented as follows:

#include <yorel/yomm2/keywords.hpp> #include <memory> class Thing {  public:  virtual ~Thing() {} }; class Asteroid : public Thing { }; class Spaceship : public Thing { }; register_classes(Thing, Spaceship, Asteroid); declare_method(void, collideWith, (virtual_<Thing&>, virtual_<Thing&>)); define_method(void, collideWith, (Thing& left, Thing& right)) {  // default collision handling } define_method(void, collideWith, (Asteroid& left, Asteroid& right)) {  // handle Asteroid-Asteroid collision } define_method(void, collideWith, (Asteroid& left, Spaceship& right)) {  // handle Asteroid-Spaceship collision } define_method(void, collideWith, (Spaceship& left, Asteroid& right)) {  // handle Spaceship-Asteroid collision } define_method(void, collideWith, (Spaceship& left, Spaceship& right)) {  // handle Spaceship-Spaceship collision } int main() {  yorel::yomm2::update_methods();  std::unique_ptr<Thing> a1(std::make_unique<Asteroid>()),  a2(std::make_unique<Asteroid>());  std::unique_ptr<Thing> s1(std::make_unique<Spaceship>()),  s2(std::make_unique<Spaceship>());  // note: types partially erased  collideWith(*a1, *a2); // Asteroid-Asteroid collision  collideWith(*a1, *s1); // Asteroid-Spaceship collision  collideWith(*s1, *a1); // Spaceship-Asteroid collision  collideWith(*s1, *s2); // Spaceship-Spaceship collision  return 0; } 

Stroustrup mentions in The Design and Evolution of C++ that he liked the concept of multimethods and considered implementing it in C++ but claims to have been unable to find an efficient sample implementation (comparable to virtual functions) and resolve some possible type ambiguity problems. He then states that although the feature would still be nice to have, that it can be approximately implemented using double dispatch or a type based lookup table as outlined in the C/C++ example above so is a low priority feature for future language revisions.[22]

D edit

As of 2021, as do many other object-oriented programming languages, D natively supports only single dispatch. However, it is possible to emulate open multimethods as a library function in D. The openmethods library[23] is an example.

// Declaration Matrix plus(virtual!Matrix, virtual!Matrix); // The override for two DenseMatrix objects @method Matrix _plus(DenseMatrix a, DenseMatrix b) {  const int nr = a.rows;  const int nc = a.cols;  assert(a.nr == b.nr);  assert(a.nc == b.nc);  auto result = new DenseMatrix;  result.nr = nr;  result.nc = nc;  result.elems.length = a.elems.length;  result.elems[] = a.elems[] + b.elems[];  return result; } // The override for two DiagonalMatrix objects @method Matrix _plus(DiagonalMatrix a, DiagonalMatrix b) {  assert(a.rows == b.rows);  double[] sum;  sum.length = a.elems.length;  sum[] = a.elems[] + b.elems[];  return new DiagonalMatrix(sum); } 

Java edit

In a language with only single dispatch, such as Java, multiple dispatch can be emulated with multiple levels of single dispatch:

 

interface Collideable {  void collideWith(final Collideable other);  /* These methods would need different names in a language without method overloading. */  void collideWith(final Asteroid asteroid);  void collideWith(final Spaceship spaceship); } class Asteroid implements Collideable {  public void collideWith(final Collideable other) {  // Call collideWith on the other object.  other.collideWith(this);  }  public void collideWith(final Asteroid asteroid) {  // Handle Asteroid-Asteroid collision.  }  public void collideWith(final Spaceship spaceship) {  // Handle Asteroid-Spaceship collision.  } } class Spaceship implements Collideable {  public void collideWith(final Collideable other) {  // Call collideWith on the other object.  other.collideWith(this);  }  public void collideWith(final Asteroid asteroid) {  // Handle Spaceship-Asteroid collision.  }  public void collideWith(final Spaceship spaceship) {  // Handle Spaceship-Spaceship collision.  } } 

Run time instanceof checks at one or both levels can also be used.

Support in programming languages edit

Primary paradigm edit

Supporting general multimethods edit

Via extensions edit

  • Any .NET language (via the library MultiMethods.NET)
  • C (via the library C Object System)
  • C# (via the library multimethod-sharp)
  • C++ (via the library yomm2, multimethods and omm)
  • D (via the library openmethods)
  • Factor (via the standard multimethods vocabulary)
  • Java (using the extension MultiJava)
  • JavaScript (via package @arrows/multimethod)
  • Perl (via the module Class::Multimethods)
  • Python (via PEAK-Rules, , , PyMultimethods, multipledispatch, or plum-dispatch)
  • Racket (via multimethod-lib)
  • Ruby (via the library The Multiple Dispatch Library and Multimethod Package and Vlx-Multimethods Package)
  • Scheme (via e.g. TinyCLOS)
  • TypeScript (via package @arrows/multimethod)

See also edit

References edit

  1. ^ Ranka, Sanjay; Banerjee, Arunava; Biswas, Kanad Kishore; Dua, Sumeet; Mishra, Prabhat; Moona, Rajat (2010-07-26). Contemporary Computing: Second International Conference, IC3 2010, Noida, India, August 9–11, 2010. Proceedings. Springer. ISBN 9783642148248.
  2. ^ a b c d e f g h i j k Muschevici, Radu; Potanin, Alex; Tempero, Ewan; Noble, James (2008). "Multiple dispatch in practice". Proceedings of the 23rd ACM SIGPLAN conference on Object-oriented programming systems languages and applications. OOPSLA '08. Nashville, TN, USA: ACM. pp. 563–582. doi:10.1145/1449764.1449808. ISBN 9781605582153. S2CID 7605233.
  3. ^ a b c d e Bezanson, Jeff; Edelman, Alan; Karpinski, Stefan; Shah, Viral B. (7 February 2017). "Julia: A fresh approach to numerical computing". SIAM Review. 59 (1): 65–98. arXiv:1411.1607. doi:10.1137/141000671. S2CID 13026838.
  4. ^ Castagna, Giuseppe; Ghelli, Giorgio & Longo, Giuseppe (1995). "A calculus for overloaded functions with subtyping". Information and Computation. 117 (1): 115–135. doi:10.1006/inco.1995.1033.
  5. ^ Castagna, Giuseppe (1996). Object-Oriented Programming: A Unified Foundation. Progress in Theoretical Computer Science. Birkhäuser. p. 384. ISBN 978-0-8176-3905-1.
  6. ^ Castagna, Giuseppe (1995). "Covariance and contravariance: conflict without a cause". ACM Transactions on Programming Languages and Systems. 17 (3): 431–447. CiteSeerX 10.1.1.115.5992. doi:10.1145/203095.203096. S2CID 15402223.
  7. ^ Bruce, Kim; Cardelli, Luca; Castagna, Giuseppe; Leavens, Gary T.; Pierce, Benjamin (1995). "On binary methods". Theory and Practice of Object Systems. 1 (3): 221–242. doi:10.1002/j.1096-9942.1995.tb00019.x. Retrieved 2013-04-19.
  8. ^ "Using type dynamic (C# Programming Guide)". Retrieved 2020-05-14.
  9. ^ "Basic concepts". Retrieved 2020-05-14.
  10. ^ "Dynamic .NET - Understanding the Dynamic Keyword in C# 4". Retrieved 2020-05-14.
  11. ^ Groovy - Multi-methods
  12. ^ @arrows/multimethod Multiple dispatch in JavaScript/TypeScript with configurable dispatch resolution by Maciej Cąderek.
  13. ^ Coady, Aric, multimethod: Multiple argument dispatching., retrieved 2021-01-28
  14. ^ multimethods.py 2005-03-09 at the Wayback Machine, Multiple dispatch in Python with configurable dispatch resolution by David Mertz, et al.
  15. ^ "Five-minute Multimethods in Python".
  16. ^ "PEAK-Rules 0.5a1.dev". Python Package Index. Retrieved 21 March 2014.
  17. ^ "PyProtocols". Python Enterprise Application Kit. Retrieved 26 April 2019.
  18. ^ "Reg". Read the docs. Retrieved 26 April 2019.
  19. ^ "C Object System: A framework that brings C to the level of other high level programming languages and beyond: CObjectSystem/COS". GitHub. 2019-02-19.
  20. ^ "Report on language support for Multi-Methods and Open-Methods for C ++" (PDF). 2007-03-11. Multiple dispatch – the selection of a function to be invoked based on the dynamic type of two or more arguments – is a solution to several classical problems in object-oriented programming.
  21. ^ yomm2, Fast, Orthogonal Open Multi-Methods for C++ by Jean-Louis Leroy.
  22. ^ Stroustrup, Bjarne (1994). "Section 13.8". The Design and Evolution of C++. Indianapolis, IN, U.S.A: Addison Wesley. Bibcode:1994dec..book.....S. ISBN 978-0-201-54330-8.
  23. ^ openmethods, Open Multi-Methods for D by Jean-Louis Leroy.
  24. ^ . The Julia Manual. Julialang. Archived from the original on 17 July 2016. Retrieved 11 May 2014.
  25. ^ "Multimethods in C# 4.0 With 'Dynamic'". Retrieved 2009-08-20.
  26. ^ "Cecil Language". Retrieved 2008-04-13.
  27. ^ "Multimethods in Clojure". Retrieved 2008-09-04.
  28. ^ Steele, Guy L. (1990). "28". Common LISP: The Language. Bedford, MA, U.S.A: Digital Press. ISBN 978-1-55558-041-4.
  29. ^ "Background and Goals". Retrieved 2008-04-13.
  30. ^ "Elixir Lang | Getting Started | Modules and functions". Retrieved 2017-11-10.
  31. ^ (PDF). Archived from the original (PDF) on 2013-01-20. Retrieved 2010-04-23.
  32. ^ "Multimethods in Groovy". Retrieved 2008-04-13.
  33. ^ "Methods – LassoGuide 9.2". Retrieved 2014-11-11.
  34. ^ "Visitor Pattern Versus Multimethods". Retrieved 2008-04-13.
  35. ^ "Nim Manual: Multi-methods". Retrieved 2022-05-03.
  36. ^ "Perl 6 FAQ". Retrieved 2008-04-13.
  37. ^ "How S4 Methods Work" (PDF). Retrieved 2008-04-13.
  38. ^ "Multiple Dispatch in Seed7". Retrieved 2011-04-23.
  39. ^ "TADS 3 System Manual". Retrieved 2012-03-19.
  40. ^ "VB.Net Multiple Dispatch". Retrieved 2020-03-31.
  41. ^ "New Features in C#4.0 and VB.Net 10.0". 4 November 2010. Retrieved 2020-03-31.
  42. ^ "Notes for Programming Language Experts". Retrieved 2016-08-21.
  43. ^ "Multiple dispatch".

External links edit

  • Stroustrup, Bjarne; Solodkyy, Yuriy; Pirkelbauer, Peter (2007). Open Multi-Methods for C++ (PDF). ACM 6th International Conference on Generative Programming and Component Engineering.
  • "Dynamic multiple dispatch". docs.racket-lang.org. Retrieved 2018-03-12.

multiple, dispatch, multimethods, feature, some, programming, languages, which, function, method, dynamically, dispatched, based, time, dynamic, type, more, general, case, some, other, attribute, more, than, arguments, this, generalization, single, dispatch, p. Multiple dispatch or multimethods is a feature of some programming languages in which a function or method can be dynamically dispatched based on the run time dynamic type or in the more general case some other attribute of more than one of its arguments 1 This is a generalization of single dispatch polymorphism where a function or method call is dynamically dispatched based on the derived type of the object on which the method has been called Multiple dispatch routes the dynamic dispatch to the implementing function or method using the combined characteristics of one or more arguments Contents 1 Understanding dispatch 1 1 Data types 1 2 Issues 1 2 1 Expressiveness and modularity 1 2 2 Ambiguity 1 2 3 Efficiency 1 3 Use in practice 1 4 Theory 2 Examples 2 1 Languages with built in multiple dispatch 2 1 1 C 2 1 2 Groovy 2 1 3 Common Lisp 2 1 4 Julia 2 1 5 Raku 2 2 Extending languages with multiple dispatch libraries 2 2 1 JavaScript 2 2 2 Python 2 3 Emulating multiple dispatch 2 3 1 C 2 3 2 C 2 3 3 D 2 3 4 Java 3 Support in programming languages 3 1 Primary paradigm 3 2 Supporting general multimethods 3 3 Via extensions 4 See also 5 References 6 External linksUnderstanding dispatch editDevelopers of computer software typically organize source code into named blocks variously called subroutines procedures subprograms functions or methods The code in the function is executed by calling it executing a piece of code that references its name This transfers control temporarily to the called function when the function s execution has completed control is typically transferred back to the instruction in the caller that follows the reference Function names are usually selected so as to be descriptive of the function s purpose It is sometimes desirable to give several functions the same name often because they perform conceptually similar tasks but operate on different types of input data In such cases the name reference at the function call site is not sufficient for identifying the block of code to be executed Instead the number and type of the arguments to the function call are also used to select among several function implementations In more conventional i e single dispatch object oriented programming languages when invoking a method sending a message in Smalltalk calling a member function in C one of its arguments is treated specially and used to determine which of the potentially many classes of methods of that name is to be applied In many languages the special argument is indicated syntactically for example a number of programming languages put the special argument before a dot in making a method call special method other arguments here so that lion sound would produce a roar whereas sparrow sound would produce a chirp In contrast in languages with multiple dispatch the selected method is simply the one whose arguments match the number and type of the function call There is no special argument that owns the function method carried out in a particular call The Common Lisp Object System CLOS is an early and well known example of multiple dispatch Another notable example of the use of multiple dispatch is the Julia programming language Multiple dispatch should be distinguished from function overloading in which static typing information such as a term s declared or inferred type or base type in a language with subtyping is used to determine which of several possibilities will be used at a given call site and that determination is made at compile or link time or some other time before program execution starts and is thereafter invariant for a given deployment or run of the program Many languages such as C offer robust function overloading but do not offer dynamic multiple dispatch C only permits dynamic single dispatch through use of virtual functions Data types edit When working with languages that can discriminate data types at compile time selecting among the alternatives can occur then The act of creating such alternative functions for compile time selection is usually referred to as overloading a function In programming languages that defer data type identification until run time i e late binding selection among alternative functions must occur then based on the dynamically determined types of function arguments Functions whose alternative implementations are selected in this manner are referred to most generally as multimethods There is some run time cost associated with dynamically dispatching function calls In some languages citation needed the distinction between overloading and multimethods can be blurred with the compiler determining whether compile time selection can be applied to a given function call or whether slower run time dispatch is needed Issues edit There are several known issues with dynamic dispatch both single and multiple While many of these issues are solved for single dispatch which has been a standard feature in object oriented programming languages for decades these issues become more complicated in the multiple dispatch case Expressiveness and modularity edit In most popular programming languages source code is delivered and deployed in granules of functionality which we will here call packages actual terminology for this concept varies between language Each package may contain multiple type value and function definitions packages are often compiled separately in languages with a compilation step and a non cyclical dependency relationship may exist A complete program is a set of packages with a main package which may depend on several other packages and the whole program consisting of the transitive closure of the dependency relationship The so called expression problem relates to the ability for code in a depending package to extend behaviors functions or datatypes defined in a base package from within an including package without modifying the source to the base package Traditional single dispatch OO languages make it trivial to add new datatypes but not new functions traditional functional languages tend to have the opposite effect and multiple dispatch if implemented correctly allows both It is desirable for an implementation of multiple dispatch to have the following properties It is possible to define different cases of a multi method from within different packages without modifying the source of a base package Inclusion of another package in the program should not change the behavior of a given multi method call when the call does not use any datatypes defined in the package Conversely if a datatype is defined in a given package and a multi method extension using that type is also defined in the same package and a value of that type is passed through a base type reference or into a generic function into another package with no dependency on that package and then the multi method is invoked with that value as an argument the multi method case defined in the package which includes the type should be employed To put it another way within a given program the same multi method invoked with the same set of arguments should resolve to the same implementation regardless of the location of the call site and whether or not a given definition is in scope or visible at the point of the method call Ambiguity edit It is generally desirable that for any given invocation of a multi method there be at most one best candidate among implementation cases of the multi method and or that if there is not that this be resolved in a predictable and deterministic fashion including failure Non deterministic behavior is undesirable Assuming a set of types with a non circular subtyping relationship one can define that one implementation of a multi method is better more specific if all dynamically dispatched arguments in the first are subtypes of all dynamically dispatched arguments specified in the second and at least one is a strict subtype With single dispatch and in the absence of multiple inheritance this condition is trivially satisfied but with multiple dispatch it is possible for two or more candidates to satisfy a given actual argument list but neither is more specific than the other one dynamic argument being the subtype in one case another being the subtype in the other case This particularly can happen if two different packages neither depending on the other both extend some multi method with implementations concerning each package s types and then a third package that includes both possibly indirectly then invokes the multi method using arguments from both packages Possible resolutions include Treating any ambiguous calls as an error This might be caught at compile time or otherwise before deployment but might not be detected until runtime and produce a runtime error Ordering the arguments so e g the case with the most specific first argument is selected and subsequent arguments are not considered for ambiguity resolution unless the first argument is insufficient to resolve the issue Construction of other rules for resolving an ambiguity in one direction or another Sometimes such rules might be arbitrary and surprising In the rules for static overload resolution in C for instance a type which matches exactly is understandably considered a better match than a type which matches through a base type reference or a generic template parameter However if the only possible matches are either through a base type or a generic parameter the generic parameter is preferred over the base type a rule that sometimes produces surprising behavior Efficiency edit Efficient implementation of single dispatch including in programming languages that are separately compiled to object code and linked with a low level not language aware linker including dynamically at program load start time or even under the direction of the application code are well known The vtable method developed in C and other early OO languages where each class has an array of function pointers corresponding to that class s virtual functions is nearly as fast as a static method call requiring O 1 overhead and only one additional memory lookup even in the un optimized case However the vtable method uses the function name and not the argument type as its lookup key and does not scale to the multiple dispatch case It also depends on the object oriented paradigm of methods being features of classes not standalone entities independent of any particular datatype Efficient implementation of multiple dispatch remains an ongoing research problem Use in practice edit To estimate how often multiple dispatch is used in practice Muschevici et al 2 studied programs that use dynamic dispatch They analyzed nine applications mostly compilers written in six different languages Common Lisp Object System Dylan Cecil MultiJava Diesel and Nice Their results show that 13 32 of generic functions use the dynamic type of one argument while 2 7 6 5 of them use the dynamic type of multiple arguments The remaining 65 93 of generic functions have one concrete method overrider and thus are not considered to use the dynamic types of their arguments Further the study reports that 2 20 of generic functions had two and 3 6 had three concrete function implementations The numbers decrease rapidly for functions with more concrete overriders Multiple dispatch is used much more heavily in Julia where multiple dispatch was a central design concept from the origin of the language collecting the same statistics as Muschevici on the average number of methods per generic function it was found that the Julia standard library uses more than double the amount of overloading than in the other languages analyzed by Muschevici and more than 10 times in the case of binary operators 3 The data from these papers is summarized in the following table where the dispatch ratio DR is the average number of methods per generic function the choice ratio CR is the mean of the square of the number of methods to better measure the frequency of functions with a large number of methods 2 3 and the degree of specialization DoS is the average number of type specialized arguments per method i e the number of arguments that are dispatched on Language Average methods DR Choice ratio CR Degree of specialization DoS Cecil 2 2 33 63 30 1 06 Common Lisp CMU 2 2 03 6 34 1 17 Common Lisp McCLIM 2 2 32 15 43 1 17 Common Lisp Steel Bank 2 2 37 26 57 1 11 Diesel 2 2 07 31 65 0 71 Dylan Gwydion 2 1 74 18 27 2 14 Dylan OpenDylan 2 2 51 43 84 1 23 Julia 3 5 86 51 44 1 54 Julia operators only 3 28 13 78 06 2 01 MultiJava 2 1 50 8 92 1 02 Nice 2 1 36 3 46 0 33 Theory edit The theory of multiple dispatching languages was first developed by Castagna et al by defining a model for overloaded functions with late binding 4 5 It yielded the first formalization of the problem of covariance and contravariance of object oriented languages 6 and a solution to the problem of binary methods 7 Examples editDistinguishing multiple and single dispatch may be made clearer by an example Imagine a game that has among its user visible objects spaceships and asteroids When two objects collide the program may need to do different things according to what has just hit what Languages with built in multiple dispatch edit C edit C introduced support for dynamic multimethods in version 4 8 April 2010 using the dynamic keyword The following example demonstrates multimethods Like many other statically typed languages C also supports static method overloading 9 Microsoft expects that developers will choose static typing over dynamic typing in most scenarios 10 The dynamic keyword supports interoperability with COM objects and dynamically typed NET languages nbsp The example below uses features introduced in C 9 and C 10 using static ColliderLibrary Console WriteLine Collide new Asteroid 101 new Spaceship 300 Console WriteLine Collide new Asteroid 10 new Spaceship 10 Console WriteLine Collide new Spaceship 101 new Spaceship 10 string Collide SpaceObject x SpaceObject y gt x Size gt 100 amp amp y Size gt 100 Big boom CollideWith x as dynamic y as dynamic Dynamic dispatch to CollideWith method class ColliderLibrary public static string CollideWith Asteroid x Asteroid y gt a a public static string CollideWith Asteroid x Spaceship y gt a s public static string CollideWith Spaceship x Asteroid y gt s a public static string CollideWith Spaceship x Spaceship y gt s s abstract record SpaceObject int Size record Asteroid int Size SpaceObject Size record Spaceship int Size SpaceObject Size Output Big boom a s s s Groovy edit Groovy is a general purpose Java compatible interusable JVM language which contrary to Java uses late binding multiple dispatch 11 Groovy implementation of C example above Late binding works the same when using non static methods or compiling class methods statically CompileStatic annotation class Program static void main String args println Collider collide new Asteroid 101 new Spaceship 300 println Collider collide new Asteroid 10 new Spaceship 10 println Collider collide new Spaceship 101 new Spaceship 10 class Collider static String collide SpaceObject x SpaceObject y x size gt 100 amp amp y size gt 100 big boom collideWith x y Dynamic dispatch to collideWith method private static String collideWith Asteroid x Asteroid y a a private static String collideWith Asteroid x Spaceship y a s private static String collideWith Spaceship x Asteroid y s a private static String collideWith Spaceship x Spaceship y s s class SpaceObject int size SpaceObject int size this size size InheritConstructors class Asteroid extends SpaceObject InheritConstructors class Spaceship extends SpaceObject Common Lisp edit In a language with multiple dispatch such as Common Lisp it might look more like this Common Lisp example shown defmethod collide with x asteroid y asteroid deal with asteroid hitting asteroid defmethod collide with x asteroid y spaceship deal with asteroid hitting spaceship defmethod collide with x spaceship y asteroid deal with spaceship hitting asteroid defmethod collide with x spaceship y spaceship deal with spaceship hitting spaceship and similarly for the other methods Explicit testing and dynamic casting are not used In the presence of multiple dispatch the traditional idea of methods as being defined in classes and contained in objects becomes less appealing each collide with method above is attached to two different classes not one Hence the special syntax for method invocation generally disappears so that method invocation looks exactly like ordinary function invocation and methods are grouped not in classes but in generic functions Julia edit Julia has built in multiple dispatch and it is central to the language design 3 The Julia version of the example above might look like abstract type SpaceObject end struct Asteroid lt SpaceObject size Int end struct Spaceship lt SpaceObject size Int end collide with Asteroid Spaceship a s collide with Spaceship Asteroid s a collide with Spaceship Spaceship s s collide with Asteroid Asteroid a a collide x SpaceObject y SpaceObject x size gt 100 amp amp y size gt 100 Big boom collide with x y Output julia gt collide Asteroid 101 Spaceship 300 Big boom julia gt collide Asteroid 10 Spaceship 10 a s julia gt collide Spaceship 101 Spaceship 10 s s Raku edit Raku like Perl uses proven ideas from other languages and type systems have shown themselves to offer compelling advantages in compiler side code analysis and powerful user side semantics via multiple dispatch It has both multimethods and multisubs Since most operators are subroutines it also has multiple dispatched operators Along with the usual type constraints it also has where constraints that allow making very specialized subroutines subset Mass of Real where 0 Inf role Stellar Object has Mass mass is required method name returns Str class Asteroid does Stellar Object method name an asteroid class Spaceship does Stellar Object has Str name some unnamed spaceship my Str destroyed lt obliterated destroyed mangled gt my Str damaged damaged collided with was damaged by We add multi candidates to the numeric comparison operators because we are comparing them numerically but makes no sense to have the objects coerce to a Numeric type If they did coerce we wouldn t necessarily need to add these operators We could have also defined entirely new operators this same way multi sub infix lt gt Stellar Object D a Stellar Object D b a mass lt gt b mass multi sub infix lt Stellar Object D a Stellar Object D b a mass lt b mass multi sub infix gt Stellar Object D a Stellar Object D b a mass gt b mass multi sub infix Stellar Object D a Stellar Object D b a mass b mass Define a new multi dispatcher and add some type constraints to the parameters If we didn t define it we would have gotten a generic one that didn t have constraints proto sub collide Stellar Object D Stellar Object D No need to repeat the types here since they are the same as the prototype The where constraint technically only applies to b not the whole signature Note that the where constraint uses the lt operator candidate we added earlier multi sub collide a b where a lt b say a name was destroyed pick by b name multi sub collide a b where a gt b redispatch to the previous candidate with the arguments swapped samewith b a This has to be after the first two because the other ones have where constraints which get checked in the order the subs were written This one would always match multi sub collide a b randomize the order my n1 n2 a name b name pick say n1 damaged pick n2 The following two candidates can be anywhere after the proto because they have more specialized types than the preceding three If the ships have unequal mass one of the first two candidates gets called instead multi sub collide Spaceship a Spaceship b where a b my n1 n2 a name b name pick say n1 collided with n2 and both ships were destroyed pick left damaged pick You can unpack the attributes into variables within the signature You could even have a constraint on them mass a where 10 multi sub collide Asteroid mass a Asteroid mass b say two asteroids collided and combined into one larger asteroid of mass a b my Spaceship Enterprise new mass 1 name The Enterprise collide Asteroid new mass 1 Enterprise collide Enterprise Spaceship new mass 1 collide Enterprise Asteroid new mass 1 collide Enterprise Spaceship new mass 1 collide Asteroid new mass 10 Asteroid new mass 5 Extending languages with multiple dispatch libraries edit JavaScript edit In languages that do not support multiple dispatch at the language definition or syntactic level it is often possible to add multiple dispatch using a library extension JavaScript and TypeScript do not support multimethods at the syntax level but it is possible to add multiple dispatch via a library For example the multimethod package 12 provides an implementation of multiple dispatch generic functions Dynamically typed version in JavaScript import multi method from arrows multimethod class Asteroid class Spaceship const collideWith multi method Asteroid Asteroid x y gt deal with asteroid hitting asteroid method Asteroid Spaceship x y gt deal with asteroid hitting spaceship method Spaceship Asteroid x y gt deal with spaceship hitting asteroid method Spaceship Spaceship x y gt deal with spaceship hitting spaceship Statically typed version in TypeScript import multi method Multi from arrows multimethod class Asteroid class Spaceship type CollideWith Multi amp x Asteroid y Asteroid void x Asteroid y Spaceship void x Spaceship y Asteroid void x Spaceship y Spaceship void const collideWith CollideWith multi method Asteroid Asteroid x y gt deal with asteroid hitting asteroid method Asteroid Spaceship x y gt deal with asteroid hitting spaceship method Spaceship Asteroid x y gt deal with spaceship hitting asteroid method Spaceship Spaceship x y gt deal with spaceship hitting spaceship Python edit Multiple dispatch can be added to Python using a library extension For example using the module multimethod py 13 and also with the module multimethods py 14 which provides CLOS style multimethods for Python without changing the underlying syntax or keywords of the language from multimethods import Dispatch from game objects import Asteroid Spaceship from game behaviors import as func ss func sa func collide Dispatch collide add rule Asteroid Spaceship as func collide add rule Spaceship Spaceship ss func collide add rule Spaceship Asteroid sa func def aa func a b Behavior when asteroid hits asteroid define new behavior collide add rule Asteroid Asteroid aa func later collide thing1 thing2 Functionally this is very similar to the CLOS example but the syntax is conventional Python Using Python 2 4 decorators Guido van Rossum produced a sample implementation of multimethods 15 with a simplified syntax multimethod Asteroid Asteroid def collide a b Behavior when asteroid hits a asteroid define new behavior multimethod Asteroid Spaceship def collide a b Behavior when asteroid hits a spaceship define new behavior define other multimethod rules and then it goes on to define the multimethod decorator The PEAK Rules package provides multiple dispatch with a syntax similar to the above example 16 It was later replaced by PyProtocols 17 The Reg library also supports multiple and predicate dispatch 18 With the introduction of type hints multiple dispatch is possible with even simpler syntax For example using plum dispatch from plum import dispatch dispatch def collide a Asteroid b Asteroid Behavior when asteroid hits a asteroid define new behavior dispatch def collide a Asteroid b Spaceship Behavior when asteroid hits a spaceship define new behavior define further rules Emulating multiple dispatch edit C edit C does not have dynamic dispatch so it must be implemented manually in some form Often an enum is used to identify the subtype of an object Dynamic dispatch can be done by looking up this value in a function pointer branch table Here is a simple example in C typedef void CollisionCase void void collision AA void handle Asteroid Asteroid collision void collision AS void handle Asteroid Spaceship collision void collision SA void handle Spaceship Asteroid collision void collision SS void handle Spaceship Spaceship collision typedef enum THING ASTEROID 0 THING SPACESHIP THING COUNT not a type of thing itself instead used to find number of things Thing CollisionCase collisionCases THING COUNT THING COUNT amp collision AA amp collision AS amp collision SA amp collision SS void collide Thing a Thing b collisionCases a b int main void collide THING SPACESHIP THING ASTEROID With the C Object System library 19 C does support dynamic dispatch similar to CLOS It is fully extensible and does not need any manual handling of the methods Dynamic message methods are dispatched by the dispatcher of COS which is faster than Objective C Here is an example in COS include lt stdio h gt include lt cos Object h gt include lt cos gen object h gt classes defclass Asteroid data members endclass defclass Spaceship data members endclass generics defgeneric Bool collide with 1 2 multimethods defmethod Bool collide with Asteroid Asteroid deal with asteroid hitting asteroid endmethod defmethod Bool collide with Asteroid Spaceship deal with asteroid hitting spaceship endmethod defmethod Bool collide with Spaceship Asteroid deal with spaceship hitting asteroid endmethod defmethod Bool collide with Spaceship Spaceship deal with spaceship hitting spaceship endmethod example of use int main void OBJ a gnew Asteroid OBJ s gnew Spaceship printf lt a a gt d n collide with a a printf lt a s gt d n collide with a s printf lt s a gt d n collide with s a printf lt s s gt d n collide with s s grelease a grelease s C edit As of 2021 update C natively supports only single dispatch though adding multi methods multiple dispatch was proposed by Bjarne Stroustrup and collaborators in 2007 20 The methods of working around this limit are analogous use either the visitor pattern dynamic cast or a library Example using run time type comparison via dynamic cast struct Thing virtual void collideWith Thing amp other 0 struct Asteroid Thing void collideWith Thing amp other dynamic cast to a pointer type returns NULL if the cast fails dynamic cast to a reference type would throw an exception on failure if auto asteroid dynamic cast lt Asteroid gt amp other handle Asteroid Asteroid collision else if auto spaceship dynamic cast lt Spaceship gt amp other handle Asteroid Spaceship collision else default collision handling here struct Spaceship Thing void collideWith Thing amp other if auto asteroid dynamic cast lt Asteroid gt amp other handle Spaceship Asteroid collision else if auto spaceship dynamic cast lt Spaceship gt amp other handle Spaceship Spaceship collision else default collision handling here or pointer to method lookup table include lt cstdint gt include lt typeinfo gt include lt unordered map gt class Thing protected Thing std uint32 t cid tid cid const std uint32 t tid type id typedef void Thing CollisionHandler Thing amp other typedef std unordered map lt std uint64 t CollisionHandler gt CollisionHandlerMap static void addHandler std uint32 t id1 std uint32 t id2 CollisionHandler handler collisionCases insert CollisionHandlerMap value type key id1 id2 handler static std uint64 t key std uint32 t id1 std uint32 t id2 return std uint64 t id1 lt lt 32 id2 static CollisionHandlerMap collisionCases public void collideWith Thing amp other auto handler collisionCases find key tid other tid if handler collisionCases end this gt handler gt second other pointer to method call else default collision handling class Asteroid public Thing void asteroid collision Thing amp other handle Asteroid Asteroid collision void spaceship collision Thing amp other handle Asteroid Spaceship collision public Asteroid Thing cid static void initCases static const std uint32 t cid class Spaceship public Thing void asteroid collision Thing amp other handle Spaceship Asteroid collision void spaceship collision Thing amp other handle Spaceship Spaceship collision public Spaceship Thing cid static void initCases static const std uint32 t cid class id Thing CollisionHandlerMap Thing collisionCases const std uint32 t Asteroid cid typeid Asteroid hash code const std uint32 t Spaceship cid typeid Spaceship hash code void Asteroid initCases addHandler cid cid CollisionHandler amp Asteroid asteroid collision addHandler cid Spaceship cid CollisionHandler amp Asteroid spaceship collision void Spaceship initCases addHandler cid Asteroid cid CollisionHandler amp Spaceship asteroid collision addHandler cid cid CollisionHandler amp Spaceship spaceship collision int main Asteroid initCases Spaceship initCases Asteroid a1 a2 Spaceship s1 s2 a1 collideWith a2 a1 collideWith s1 s1 collideWith s2 s1 collideWith a1 The YOMM2 library 21 provides a fast orthogonal implementation of open multimethods The syntax for declaring open methods is inspired by a proposal for a native C implementation The library requires that the user registers all the classes used as virtual arguments and their sub classes but does not require any modifications to existing code Methods are implemented as ordinary inline C functions they can be overloaded and they can be passed by pointer There is no limit on the number of virtual arguments and they can be arbitrarily mixed with non virtual arguments The library uses a combination of techniques compressed dispatch tables collision free integer hash table to implement method calls in constant time while mitigating memory usage Dispatching a call to an open method with a single virtual argument takes only 15 30 more time than calling an ordinary virtual member function when a modern optimizing compiler is used The Asteroids example can be implemented as follows include lt yorel yomm2 keywords hpp gt include lt memory gt class Thing public virtual Thing class Asteroid public Thing class Spaceship public Thing register classes Thing Spaceship Asteroid declare method void collideWith virtual lt Thing amp gt virtual lt Thing amp gt define method void collideWith Thing amp left Thing amp right default collision handling define method void collideWith Asteroid amp left Asteroid amp right handle Asteroid Asteroid collision define method void collideWith Asteroid amp left Spaceship amp right handle Asteroid Spaceship collision define method void collideWith Spaceship amp left Asteroid amp right handle Spaceship Asteroid collision define method void collideWith Spaceship amp left Spaceship amp right handle Spaceship Spaceship collision int main yorel yomm2 update methods std unique ptr lt Thing gt a1 std make unique lt Asteroid gt a2 std make unique lt Asteroid gt std unique ptr lt Thing gt s1 std make unique lt Spaceship gt s2 std make unique lt Spaceship gt note types partially erased collideWith a1 a2 Asteroid Asteroid collision collideWith a1 s1 Asteroid Spaceship collision collideWith s1 a1 Spaceship Asteroid collision collideWith s1 s2 Spaceship Spaceship collision return 0 Stroustrup mentions in The Design and Evolution of C that he liked the concept of multimethods and considered implementing it in C but claims to have been unable to find an efficient sample implementation comparable to virtual functions and resolve some possible type ambiguity problems He then states that although the feature would still be nice to have that it can be approximately implemented using double dispatch or a type based lookup table as outlined in the C C example above so is a low priority feature for future language revisions 22 D edit As of 2021 update as do many other object oriented programming languages D natively supports only single dispatch However it is possible to emulate open multimethods as a library function in D The openmethods library 23 is an example Declaration Matrix plus virtual Matrix virtual Matrix The override for two DenseMatrix objects method Matrix plus DenseMatrix a DenseMatrix b const int nr a rows const int nc a cols assert a nr b nr assert a nc b nc auto result new DenseMatrix result nr nr result nc nc result elems length a elems length result elems a elems b elems return result The override for two DiagonalMatrix objects method Matrix plus DiagonalMatrix a DiagonalMatrix b assert a rows b rows double sum sum length a elems length sum a elems b elems return new DiagonalMatrix sum Java edit In a language with only single dispatch such as Java multiple dispatch can be emulated with multiple levels of single dispatch nbsp interface Collideable void collideWith final Collideable other These methods would need different names in a language without method overloading void collideWith final Asteroid asteroid void collideWith final Spaceship spaceship class Asteroid implements Collideable public void collideWith final Collideable other Call collideWith on the other object other collideWith this public void collideWith final Asteroid asteroid Handle Asteroid Asteroid collision public void collideWith final Spaceship spaceship Handle Asteroid Spaceship collision class Spaceship implements Collideable public void collideWith final Collideable other Call collideWith on the other object other collideWith this public void collideWith final Asteroid asteroid Handle Spaceship Asteroid collision public void collideWith final Spaceship spaceship Handle Spaceship Spaceship collision Run time instanceof checks at one or both levels can also be used Support in programming languages editPrimary paradigm edit Julia 24 Supporting general multimethods edit C 4 0 25 Cecil 26 Clojure 27 Common Lisp via the Common Lisp Object System 28 Dylan 29 Emacs Lisp via cl defmethod Elixir 30 Fortress 31 Groovy 32 Lasso 33 34 Nim up to v0 19 x from v0 20 0 it is necessary to pass a compiler flag 35 Raku 36 R 37 Seed7 38 TADS 39 VB Net 40 via late binding also via Net DLR 41 Wolfram Language 42 via symbolic pattern matching Xtend 43 Via extensions edit Any NET language via the library MultiMethods NET C via the library C Object System C via the library multimethod sharp C via the library yomm2 multimethods and omm D via the library openmethods Factor via the standard multimethods vocabulary Java using the extension MultiJava JavaScript via package arrows multimethod Perl via the module Class Multimethods Python via PEAK Rules RuleDispatch gnosis magic multimethods PyMultimethods multipledispatch or plum dispatch Racket via multimethod lib Ruby via the library The Multiple Dispatch Library and Multimethod Package and Vlx Multimethods Package Scheme via e g TinyCLOS TypeScript via package arrows multimethod See also editPredicate dispatchReferences edit Ranka Sanjay Banerjee Arunava Biswas Kanad Kishore Dua Sumeet Mishra Prabhat Moona Rajat 2010 07 26 Contemporary Computing Second International Conference IC3 2010 Noida India August 9 11 2010 Proceedings Springer ISBN 9783642148248 a b c d e f g h i j k Muschevici Radu Potanin Alex Tempero Ewan Noble James 2008 Multiple dispatch in practice Proceedings of the 23rd ACM SIGPLAN conference on Object oriented programming systems languages and applications OOPSLA 08 Nashville TN USA ACM pp 563 582 doi 10 1145 1449764 1449808 ISBN 9781605582153 S2CID 7605233 a b c d e Bezanson Jeff Edelman Alan Karpinski Stefan Shah Viral B 7 February 2017 Julia A fresh approach to numerical computing SIAM Review 59 1 65 98 arXiv 1411 1607 doi 10 1137 141000671 S2CID 13026838 Castagna Giuseppe Ghelli Giorgio amp Longo Giuseppe 1995 A calculus for overloaded functions with subtyping Information and Computation 117 1 115 135 doi 10 1006 inco 1995 1033 Castagna Giuseppe 1996 Object Oriented Programming A Unified Foundation Progress in Theoretical Computer Science Birkhauser p 384 ISBN 978 0 8176 3905 1 Castagna Giuseppe 1995 Covariance and contravariance conflict without a cause ACM Transactions on Programming Languages and Systems 17 3 431 447 CiteSeerX 10 1 1 115 5992 doi 10 1145 203095 203096 S2CID 15402223 Bruce Kim Cardelli Luca Castagna Giuseppe Leavens Gary T Pierce Benjamin 1995 On binary methods Theory and Practice of Object Systems 1 3 221 242 doi 10 1002 j 1096 9942 1995 tb00019 x Retrieved 2013 04 19 Using type dynamic C Programming Guide Retrieved 2020 05 14 Basic concepts Retrieved 2020 05 14 Dynamic NET Understanding the Dynamic Keyword in C 4 Retrieved 2020 05 14 Groovy Multi methods arrows multimethod Multiple dispatch in JavaScript TypeScript with configurable dispatch resolution by Maciej Caderek Coady Aric multimethod Multiple argument dispatching retrieved 2021 01 28 multimethods py Archived 2005 03 09 at the Wayback Machine Multiple dispatch in Python with configurable dispatch resolution by David Mertz et al Five minute Multimethods in Python PEAK Rules 0 5a1 dev Python Package Index Retrieved 21 March 2014 PyProtocols Python Enterprise Application Kit Retrieved 26 April 2019 Reg Read the docs Retrieved 26 April 2019 C Object System A framework that brings C to the level of other high level programming languages and beyond CObjectSystem COS GitHub 2019 02 19 Report on language support for Multi Methods and Open Methods for C PDF 2007 03 11 Multiple dispatch the selection of a function to be invoked based on the dynamic type of two or more arguments is a solution to several classical problems in object oriented programming yomm2 Fast Orthogonal Open Multi Methods for C by Jean Louis Leroy Stroustrup Bjarne 1994 Section 13 8 The Design and Evolution of C Indianapolis IN U S A Addison Wesley Bibcode 1994dec book S ISBN 978 0 201 54330 8 openmethods Open Multi Methods for D by Jean Louis Leroy Methods The Julia Manual Julialang Archived from the original on 17 July 2016 Retrieved 11 May 2014 Multimethods in C 4 0 With Dynamic Retrieved 2009 08 20 Cecil Language Retrieved 2008 04 13 Multimethods in Clojure Retrieved 2008 09 04 Steele Guy L 1990 28 Common LISP The Language Bedford MA U S A Digital Press ISBN 978 1 55558 041 4 Background and Goals Retrieved 2008 04 13 Elixir Lang Getting Started Modules and functions Retrieved 2017 11 10 The Fortress Language Specification Version 1 0 PDF Archived from the original PDF on 2013 01 20 Retrieved 2010 04 23 Multimethods in Groovy Retrieved 2008 04 13 Methods LassoGuide 9 2 Retrieved 2014 11 11 Visitor Pattern Versus Multimethods Retrieved 2008 04 13 Nim Manual Multi methods Retrieved 2022 05 03 Perl 6 FAQ Retrieved 2008 04 13 How S4 Methods Work PDF Retrieved 2008 04 13 Multiple Dispatch in Seed7 Retrieved 2011 04 23 TADS 3 System Manual Retrieved 2012 03 19 VB Net Multiple Dispatch Retrieved 2020 03 31 New Features in C 4 0 and VB Net 10 0 4 November 2010 Retrieved 2020 03 31 Notes for Programming Language Experts Retrieved 2016 08 21 Multiple dispatch External links editStroustrup Bjarne Solodkyy Yuriy Pirkelbauer Peter 2007 Open Multi Methods for C PDF ACM 6th International Conference on Generative Programming and Component Engineering Dynamic multiple dispatch docs racket lang org Retrieved 2018 03 12 Retrieved from https en wikipedia org w index php title Multiple dispatch amp oldid 1207082771, wikipedia, wiki, book, books, library,

article

, read, download, free, free download, mp3, video, mp4, 3gp, jpg, jpeg, gif, png, picture, music, song, movie, book, game, games.