# 多分派

## 例子

### 具有内建多分派的语言

#### Common Lisp

```(defgeneric collide (x y))
(defclass asteroid () ())
(defclass spaceship () ())
(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
)
```

#### Julia

Julia有内建的多分派，并且它是语言设计的中心[3]。Julia版本的例子如下：

```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
```

#### C#

C#在版本4（2010年4月），使用关键字`dynamic`，介入了对动态多方法的支持[4]。下面的例子展示多方法协同于在版本8（2019年9月）中介入的`switch`表达式[5]。像很多其他静态类型的语言语言一样，C#还支持静态方法重载[6]，Microsoft预期开发者在多数场景下会选用静态类型超过动态类型[7]`dynamic`关键字支持COM对象和动态类型的.NET语言的互操作。

```class Program
{
static void Main()
{
Console.WriteLine(Collider.Collide(new Asteroid(101),  new Spaceship(300)));
Console.WriteLine(Collider.Collide(new Asteroid(10),   new Spaceship(10)));
Console.WriteLine(Collider.Collide(new Spaceship(101), new Spaceship(10)));
}
}

static class Collider
{
public static string Collide(SpaceObject x, SpaceObject y) =>
((x.Size > 100) && (y.Size > 100)) ?
"Big boom!" : CollideWith(x as dynamic, y as dynamic);
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";
}

abstract class SpaceObject
{
public SpaceObject(int size) => Size = size;

public int Size { get; }
}

class Asteroid : SpaceObject
{
public Asteroid(int size) : base(size) { }
}

class Spaceship : SpaceObject
{
public Spaceship(int size) : base(size) { }
}
```

```big-boom
a/s
s/s
```

#### Groovy

Groovy是通用的Java兼容/互用的JVM语言，它对立于Java，使用后期绑定/多分派[8]

```/*
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 {}
```

### 用多分派库扩展的语言

#### JavaScript

JavaScriptTypeScript不在语言语法层次上支持多方法，但可以通过库来增加多分派。例如，使用multimethod包[9]，它提供了多分派、泛化函数的实现。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
}),
)
```

TypeScript有对应的静态类型版本。[a]

#### Python

```from multimethod import multimethod

class Asteroid(): pass

class Spaceship(): pass

@multimethod
def collide_with(x: Asteroid, y: Asteroid):
'''deal with asteroid hitting asteroid'''
print("asteroid hitting asteroid")

@multimethod
def collide_with(x: Asteroid, y: Spaceship):
'''deal with asteroid hitting spaceship'''
print("asteroid hitting spaceship")

@multimethod
def collide_with(x: Spaceship, y: Asteroid):
'''deal with spaceship hitting asteroid'''
print("spaceship hitting asteroid")

@multimethod
def collide_with(x: Spaceship, y: Spaceship):
'''deal with spaceship hitting spaceship'''
print("spaceship hitting spaceship")
```
```>>> a = Asteroid()
>>> b = Spaceship()
>>> collide_with(a, b)
asteroid hitting spaceship
```

#### C

C语言使用C Object System库[17]，可以支持类似于CLOS的动态分派。它是完全可扩展的并且方法不需要任何的手工处理。动态消息（方法）通过COS分派器来分派，它比Objective-C更快。下面是使用COS的例子：

```#include <stdio.h>
#include <cos/Object.h>
#include <cos/gen/object.h>

/* 类 */
defclass (Asteroid)
/* 数据成员 */
endclass

defclass (Spaceship)
/* 数据成员 */
endclass

/* 泛化函数 */
defgeneric (_Bool, collide_with, _1, _2);

/* 多方法 */
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

/* 用例 */
int main(int argc, char *argv[])
{
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

C语言没有动态分派，也可以不使用C Object System库，而以某种形式手工实现。动态分派经常使用`enum`来标识一个对象的子类型，然后可通过在函数指针分支表英语branch table中查找这个值来完成。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);
}
```

### Java

```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.
}
}
```

## 代码示例

1. ^ 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
}),
)
```
2. ^ Python的multimethods.py示例：
```from multimethods import Dispatch
from game_objects import Asteroid, Spaceship
from game_behaviors import as_func, ss_func, sa_func
collide = Dispatch()
def aa_func(a, b):
"""Behavior when asteroid hits asteroid."""
# ...define new behavior...
```
```# ...later...
collide(thing1, thing2)
```
3. ^ Python的van Rossum最初的多方法实现：
```@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 ...
```

## 引用

1. ^ Ranka, Sanjay; Banerjee, Arunava; Biswas, Kanad Kishore; Dua, Sumeet; Mishra, Prabhat; Moona, Rajat. Contemporary Computing: Second International Conference, IC3 2010, Noida, India, August 9–11, 2010. Proceedings. Springer. 2010-07-26 [2021-03-23]. ISBN 9783642148248. （原始内容存档于2021-04-27）.
3. ^ Bezanson, Jeff; Edelman, Alan; Karpinski, Stefan; Shah, Viral B. Julia: A fresh approach to numerical computing. SIAM Review. 7 February 2017, 59 (1): 65–98. . doi:10.1137/141000671.
4. ^ Using type dynamic (C# Programming Guide). [2020-05-14]. （原始内容存档于2021-05-26）.
5. ^ switch expression (C# reference). [2020-05-14]. （原始内容存档于2021-06-28）.
6. ^ Basic concepts. [2020-05-14]. （原始内容存档于2021-04-16）.
7. ^ Dynamic .NET - Understanding the Dynamic Keyword in C# 4. [2020-05-14]. （原始内容存档于2021-05-24）.
8. ^ Groovy - Multi-methods. [2021-04-15]. （原始内容存档于2021-04-16）.
9. @arrows/multimethod页面存档备份，存于互联网档案馆） Multiple dispatch in JavaScript/TypeScript with configurable dispatch resolution by Maciej Cąderek.
10. ^ multimethods.py页面存档备份，存于互联网档案馆）, Multiple dispatch in Python with configurable dispatch resolution by David Mertz, et al.
11. ^ Five-minute Multimethods in Python. [2014-07-13]. （原始内容存档于2021-05-29）.
12. multipledispatch. [2021-04-15]. （原始内容存档于2020-11-11）.
13. Coady, Aric, multimethod: Multiple argument dispatching., [2021-01-28], （原始内容存档于2020-12-31）
14. ^ PEAK-Rules 0.5a1.dev. Python Package Index. [21 March 2014]. （原始内容存档于2017-03-14）.
15. ^ PyProtocols. Python Enterprise Application Kit. [26 April 2019]. （原始内容存档于2021-05-05）.
16. Reg. Read the docs. [26 April 2019]. （原始内容存档于2021-03-05）.
17. C Object System: A framework that brings C to the level of other high level programming languages and beyond: CObjectSystem/COS. 2019-02-19 [2021-03-30]. （原始内容存档于2021-05-01）.
18. ^ Methods. The Julia Manual. Julialang. [11 May 2014]. （原始内容存档于2016-07-17）.
19. ^ Multimethods in C# 4.0 With 'Dynamic'. [2009-08-20]. （原始内容存档于2009-08-25）.
20. ^ Cecil Language. [2008-04-13]. （原始内容存档于2016-09-01）.
21. ^ Multimethods in Clojure. [2008-09-04]. （原始内容存档于2015-09-20）.
22. ^ Steele, Guy L. 28. Common LISP: The Language. Bedford, MA, U.S.A: Digital Press. 1990 [2021-03-30]. ISBN 978-1-55558-041-4. （原始内容存档于2017-12-17）.
23. ^ Background and Goals. [2008-04-13]. （原始内容存档于2020-04-04）.
24. ^ The Fortress Language Specification, Version 1.0 (PDF). [2010-04-23]. （原始内容 (PDF)存档于2013-01-20）.
25. ^ Multimethods in Groovy. [2008-04-13]. （原始内容存档于2011-08-12）.
26. ^ Methods – LassoGuide 9.2. [2014-11-11]. （原始内容存档于2021-06-13）.
27. ^ Visitor Pattern Versus Multimethods. [2008-04-13]. （原始内容存档于2021-02-05）.
28. ^ Nim Manual: Multi-methods. [2020-09-11]. （原始内容存档于2021-06-15）.
29. ^ Perl 6 FAQ. [2008-04-13]. （原始内容存档于2012-03-13）.
30. ^ How S4 Methods Work (PDF). [2008-04-13]. （原始内容存档 (PDF)于2021-05-10）.
31. ^ Multiple Dispatch in Seed7. [2011-04-23]. （原始内容存档于2021-01-29）.
32. ^ TADS 3 System Manual. [2012-03-19]. （原始内容存档于2017-02-14）.
33. ^ VB.Net Multiple Dispatch. [2020-03-31]. （原始内容存档于2021-04-11）.
34. ^ New Features in C#4.0 and VB.Net 10.0. [2020-03-31]. （原始内容存档于2021-02-01）.
35. ^ Notes for Programming Language Experts. [2016-08-21]. （原始内容存档于2021-06-26）.
36. ^ Multiple dispatch. [2021-03-30]. （原始内容存档于2021-05-08）.
37. ^ MultiMethods.NET. [2014-07-13]. （原始内容存档于2010-02-26）.
38. ^ multimethod-sharp. [2021-03-30]. （原始内容存档于2016-01-23）.
39. ^ yomm2. [2021-03-30]. （原始内容存档于2020-11-12）.
40. ^ multimethods. [2021-03-30]. （原始内容存档于2020-11-22）.
41. ^ openmethods
42. ^ multimethods vocabulary. [2014-07-13]. （原始内容存档于2021-04-29）.
43. ^ MultiJava. [2014-07-13]. （原始内容存档于2021-04-11）.
44. ^ Class::Multimethods. [2014-07-13]. （原始内容存档于2013-10-21）.
45. ^ multimethod-lib. [2021-03-30]. （原始内容存档于2021-04-29）.
46. ^ The Multiple Dispatch Library. [2021-03-30]. （原始内容存档于2021-04-30）.
47. ^ Multimethod Package. [2021-03-30]. （原始内容存档于2021-04-29）.
48. ^ Vlx-Multimethods Package. [2021-03-30]. （原始内容存档于2021-04-27）.
49. ^ TinyCLOS. [2014-07-13]. （原始内容存档于2008-12-11）.

## 外部链接

• Stroustrup, Bjarne; Solodkyy, Yuriy; Pirkelbauer, Peter. Open Multi-Methods for C++ (PDF). ACM 6th International Conference on Generative Programming and Component Engineering. 2007 [2014-07-13]. （原始内容存档 (PDF)于2021-04-29）.
• Dynamic multiple dispatch. docs.racket-lang.org. [2018-03-12]. （原始内容存档于2021-04-29）.