特设多态
特设多态(ad hoc polymorphism)是程序设计语言的一种多态,多态函数有多个不同的实现,依赖于其实参而调用相应版本的函数。因此,特设多态仅支持有限数量的不同类型。函数重载乃至运算符重载也是特设多态的一种。
概述
特设多态与参数多态相对。ad hoc在这里并不是贬义,而是指这类多态并不是类型系统的基本特性,不是像参数多态那样适用于无穷多的类型,而是针对特定问题的解决方案。
换言之,参数多态对各模板参数的实现,是根据模板的通用(generically)的行为的抽象,即泛型的语义;而特设多态可以针对不同的版本实现完全不同的行为,或曰对于每个不同的模版参数都有单独的版本来应对。打个比方:假如我们要把原材料切成两半——
- 参数多态:只要能“切”,就用工具来切割它;
- 特设多态:根据原材料是铁还是木头还是什么来选择不同的工具来切。
历史
特设多态的名字来源于其发明人克里斯托弗·斯特雷奇于1967年8月在哥本哈根的计算机程序设计暑期学校发表的著名论文《编程语言中的基础概念》,该文首次提出了参数多态、特设多态、左值、右值等概念。[1]
早绑定
多态的早绑定(early binding)是在编译期,编译器完成多态的分派机制:把多态函数、多态类型的名字根据模板参数绑定到具体的模板实现。
晚绑定
多态的晚绑定是在运行期,程序确定即将要调用的多态函数的实现。Smalltalk实现了这种晚绑定机制。
例子
加法运算符+
假设可以运用到如下的情形:
1 + 2 = 3
3.14 + 0.0015 = 3.1415
1 + 3.7 = 4.7
[1, 2, 3] + [4, 5, 6] = [1, 2, 3, 4, 5, 6]
[true, false] + [false, true] = [true, false, false, true]
"bab" + "oon" = "baboon"
重载
为此,需要的重载实现:
- 第一种情形,需要整型加法;
- 第二、第三种情形,需要浮点型加法。其中第三种情形需要隐式类型转换(type coercion)。
- 第四、第五种情形,需要list的连接操作;
- 第六种情形,需要字符串字面量的连接操作。
因此,运算符名字+
实际上使用了三到四种完全不同的函数实现。
参考文献
- ^ C. Strachey, Fundamental concepts in programming languages. Lecture notes for International Summer School in Computer Programming, Copenhagen, August 1967