Multiple dispatch: Difference between revisions
m →C: _Bool might be better for C code than bool |
use default method to simplify Java example |
||
Line 581: | Line 581: | ||
<syntaxhighlight lang=Java> |
<syntaxhighlight lang=Java> |
||
interface Collideable { |
interface Collideable { |
||
void collideWith(final Collideable other) |
default void collideWith(final Collideable other){ |
||
⚫ | |||
⚫ | |||
⚫ | |||
/* These methods would need different names in a language without method overloading. */ |
/* These methods would need different names in a language without method overloading. */ |
||
void collideWith(final Asteroid asteroid); |
void collideWith(final Asteroid asteroid); |
||
Line 588: | Line 592: | ||
class Asteroid implements Collideable { |
class Asteroid implements Collideable { |
||
public void collideWith(final Collideable other) { |
|||
⚫ | |||
⚫ | |||
⚫ | |||
public void collideWith(final Asteroid asteroid) { |
public void collideWith(final Asteroid asteroid) { |
||
// Handle Asteroid-Asteroid collision. |
// Handle Asteroid-Asteroid collision. |
||
} |
} |
||
public void collideWith(final Spaceship spaceship) { |
public void collideWith(final Spaceship spaceship) { |
||
// Handle Asteroid-Spaceship collision. |
// Handle Asteroid-Spaceship collision. |
||
Line 601: | Line 602: | ||
class Spaceship implements Collideable { |
class Spaceship implements Collideable { |
||
public void collideWith(final Collideable other) { |
|||
// Call collideWith(Spaceship) on the other object. |
|||
other.collideWith(this); |
|||
} |
|||
public void collideWith(final Asteroid asteroid) { |
public void collideWith(final Asteroid asteroid) { |
||
// Handle Spaceship-Asteroid collision. |
// Handle Spaceship-Asteroid collision. |
||
} |
} |
||
public void collideWith(final Spaceship spaceship) { |
public void collideWith(final Spaceship spaceship) { |
||
// Handle Spaceship-Spaceship collision. |
// Handle Spaceship-Spaceship collision. |
Revision as of 18:38, 6 January 2019
Polymorphism |
---|
Ad hoc polymorphism |
Parametric polymorphism |
Subtyping |
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 actual 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
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) 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 cheep.
By 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.
Data types
When working with languages that can discriminate data types at compile-time, selecting among the alternatives can occur at compile-time. 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), the selection among alternative functions must occur at run-time, 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.
Use in practice
In order 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 beginning 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 (in order 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) |
---|---|---|---|
Common Lisp (CMU)[2] | 2.03 | 6.34 | 1.17 |
Common Lisp (Steel Bank)[2] | 2.37 | 26.57 | 1.11 |
Common Lisp (McCLIM)[2] | 2.32 | 15.43 | 1.17 |
Cecil[2] | 2.33 | 63.30 | 1.06 |
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 |
Nice[2] | 1.36 | 3.46 | 0.33 |
MultiJava[2] | 1.50 | 8.92 | 1.02 |
Theory
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
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.
Multiple dispatch examples
Common Lisp
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 there 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
Julia is another language with built-in multiple dispatch, and in fact multiple dispatch is central to the design of the language.[3] The Julia version of the example above might look like:
collide_with(x::Asteroid, y::Asteroid) = ... # deal with asteroid hitting asteroid
collide_with(x::Asteroid, y::Spaceship) = ... # deal with asteroid hitting spaceship
collide_with(x::Spaceship, y::Asteroid) = ... # deal with spaceship hitting asteroid
collide_with(x::Spaceship, y::Spaceship) = ... # deal with spaceship hitting spaceship
Perl 6
Perl 6, like past versions, 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 multi methods, and multi subs. Since most operators are actually subroutines, it has multiple dispatched operators as well.
Along with the usual type constraints, it also has "where" constraints that allow you to make 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 doesn't make 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));
Python
In languages that do not support multiple dispatch at the language definition or syntactic level, such as Python, it is often possible to add multiple dispatch using a library extension. For example, the module multimethods.py[8] 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 ASFunc, SSFunc, SAFunc
collide = Dispatch()
collide.add_rule((Asteroid, Spaceship), ASFunc)
collide.add_rule((Spaceship, Spaceship), SSFunc)
collide.add_rule((Spaceship, Asteroid), SAFunc)
def AAFunc(a, b):
"""Behavior when asteroid hits asteroid"""
# ...define new behavior...
collide.add_rule((Asteroid, Asteroid), AAFunc)
# ...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[9] with a simplified syntax:
@multimethod(Asteroid, Asteroid)
def collide(a, b):
"""Behavior when asteroid hits asteroid"""
# ...define new behavior...
@multimethod(Asteroid, Spaceship)
def collide(a, b):
"""Behavior when asteroid hits 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.[10]
Examples of emulating multiple dispatch
C
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 {
asteroid = 0,
spaceship,
num_thing_types /* not a type of thing itself, instead used to find number of things */
} Thing;
CollisionCase collisionCases[num_thing_types][num_thing_types] = {
{&collision_AA, &collision_AS},
{&collision_SA, &collision_SS}
};
void collide(Thing a, Thing b) {
(*collisionCases[a][b])();
}
int main(void) {
collide(spaceship, asteroid);
}
With the C Object System library,[11] 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(b);
}
C++
As of 2018[update], C++ natively supports only single dispatch, though adding multi-dispatch is being considered.[12] The methods of working around this limitation 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[13] provides a fast, orthogonal implementation of open multi-methods.
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, perfect integer hash) 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/cute.hpp>
using yorel::yomm2::virtual_;
class Thing {
public:
virtual ~Thing() {}
// ...
};
class Asteroid : public Thing {
// ...
};
class Spaceship : public Thing {
// ...
};
register_class(Thing);
register_class(Spaceship, Thing);
register_class(Asteroid, Thing);
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();
Asteroid a1, a2;
Spaceship s1, s2;
collideWith(a1, a2);
collideWith(a1, s1);
collideWith(s1, s2);
collideWith(s1, a1);
}
Stroustrup mentions in The Design and Evolution of C++ that he liked the concept of multi-methods 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.[14]
D
As of 2018[update], like many other object-oriented programming languages, D natively supports only single dispatch. However, it is possible to emulate open multi-methods as a library solution in D. The openmethods library[15] 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
In a language with only single dispatch, such as Java, multiple dispatch can be emulated with multiple levels of single dispatch:
interface Collideable {
default void collideWith(final Collideable other){
// Call collideWith on the other object.
other.collideWith(this);
}
/* 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 Asteroid asteroid) {
// Handle Asteroid-Asteroid collision.
}
public void collideWith(final Spaceship spaceship) {
// Handle Asteroid-Spaceship collision.
}
}
class Spaceship implements Collideable {
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
Programming languages that support general multimethods:
- C# 4.0[16]
- Cecil[17]
- Clojure[18]
- Common Lisp (via the Common Lisp Object System)[19]
- Dylan[20]
- Elixir[21]
- Fortress[22]
- Groovy[23]
- Haskell via multi-parameter type classes[24]
- Julia[25]
- Lasso[26]
- Nice[27]
- Nim[28]
- Perl 6[29]
- R[30]
- Scala,[citation needed] also via multi-parameter type classes
- Seed7[31]
- TADS[32]
- Wolfram Language[33] via symbolic pattern matching
- Xtend[34]
Multimethods in other programming languages via extensions:
- .NET (via the library MultiMethods.NET)
- C (via the library C Object System)
- C# (via the library multimethod-sharp)
- C++ (via the library yomm2 and multimethods)
- D (via the library openmethods)
- Factor (via the standard multi-methods vocabulary)
- Java (using the extension MultiJava)
- Perl (via the module Class::Multimethods)
- Python (via PEAK-Rules, RuleDispatch, gnosis.magic.multimethods, PyMultimethods, or multipledispatch)
- Ruby (via the library The Multiple Dispatch Library and Multimethod Package and Vlx-Multimethods Package)
- Scheme (via e.g. TinyCLOS)
- Racket (via multimethod-lib)
Also, multi-parameter type classes in Haskell and Scala can be used to emulate multiple dispatch.
See also
References
- ^ Springer, ed. (2010-07-26). Contemporary Computing: Second International Conference, IC3 2010, Noida, India, August 9-11, 2010. Proceedings.
{{cite book}}
: Unknown parameter|authors=
ignored (help) - ^ 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: 563–582. doi:10.1145/1449764.1449808.
- ^ 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.
- ^ Giuseppe Castagna; Giorgio Ghelli; Giuseppe Longo (1995). "A calculus for overloaded functions with subtyping". Information and Computation. 117 (1). Academic press: 115–135. doi:10.1006/inco.1995.1033. Retrieved 2013-04-19.
{{cite journal}}
: Unknown parameter|last-author-amp=
ignored (|name-list-style=
suggested) (help) - ^ Castagna, Giuseppe (1996). Object-Oriented Programming: A Unified Foundation. Birkhäuser. p. 384. ISBN 978-0-8176-3905-1.
- ^ Giuseppe Castagna (1995). "Covariance and contravariance: conflict without a cause". Transactions on Programming Languages and Systems (TOPLAS). 17 (3). ACM. doi:10.1145/203095.203096. Retrieved 2013-04-19.
- ^ Kim Bruce; Luca Cardelli; Giuseppe Castagna; Gary T. Leavens; Benjamin Pierce (1995). "On binary methods". Theory and Practice of Object Systems. 1 (3). Retrieved 2013-04-19.
- ^ multimethods.py, Multiple dispatch in Python with configurable dispatch resolution by David Mertz, et al.
- ^ http://www.artima.com/weblogs/viewpost.jsp?thread=101605
- ^ "PEAK-Rules 0.5a1.dev". Python Package Index. Retrieved 21 March 2014.
- ^ https://github.com/CObjectSystem/COS
- ^ http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2216.pdf
- ^ 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. ISBN 0-201-54330-3.
- ^ openmethods, Open Multi-Methods for D by Jean-Louis Leroy.
- ^ "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). "chapter 28". Common LISP: The Language. Bedford, MA, U.S.A: Digital Press. ISBN 1-55558-041-6.
- ^ "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). Retrieved 2010-04-23.
- ^ "Multimethods in Groovy". Retrieved 2008-04-13.
- ^ "Type classes: exploring the design space". 1997-05-02.
- ^ "Methods". The Julia Manual. Julialang. Retrieved 11 May 2014.
- ^ "Methods - LassoGuide 9.2". Retrieved 2014-11-11.
- ^ "Visitor Pattern Versus Multimethods". Retrieved 2008-04-13.
- ^ "Nim Manual". Retrieved 2015-05-08.
- ^ "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.
- ^ "Notes for Programming Language Experts". Retrieved 2016-08-21.
- ^ "Multiple dispatch".
External links
- Bjarne Stroustrup; Yuriy Solodkyy; Peter Pirkelbauer (2007). Open Multi-Methods for C++ (PDF). ACM 6th International Conference on Generative Programming and Component Engineering.
- [1]
- ^ "Dynamic multiple dispatch". docs.racket-lang.org. Retrieved 2018-03-12.