5

我想知道通常是否有可能统一继承和参数多态性(“泛型”)的概念,特别是在方差方面,但在他们必须如何(“语法”)和在哪里(使用站点/声明站点)方面被定义?

考虑这个观点:

  • 子类型例如S <: T可以被视为协变行为,因为接受的输入参数T也将接受S
  • 将“继承模型的方差”更改为不变量只能在定义方面通过禁止子类型(例如final,在类定义中添加修饰符)来实现,据我在大多数情况下所见,逆变是不可能的
  • 参数多态性在默认情况下是不变的,但可以使其成为协变/反变

考虑到两者之间似乎存在不可忽略的概念不匹配

  • String[] <: Object[]允许“不安全”协变(例如在 Java/C# 中)所产生的痛苦语言
  • 与继承相比,如何声明和使用继承/参数多态性的差异

在某些语言中,可以看出两者可以很好地协同工作,例如

class Foo extends Ordered[Foo]

实现排序/比较行为。

  • 是否可以想象继承和参数多态性的概念可以统一并获得相同的默认方差行为(例如默认协方差,或者这会导致需要用不变性注释标记大多数类型,因此只是将丑陋移到另一个点)? 这是否更实用,就好像数据结构在默认情况下也会变得不可变一样?
  • 是否有一个正式的系统被证明是合理的?
  • 无论具体的编程语言如何,最有可能需要哪些语法选项/更改?
  • 是否有一些工作示例或语言已经可以使用此/类似的东西?
4

1 回答 1

4

通过协变/逆变,通常意味着这一点。假设X, Y,Z是类型。进一步假设a → b表示具有类型参数和类型a结果的函数类型b<:表示子类型关系,或者可能是“一致性”的其他概念。⇒ 箭头表示“包含”。那么以下成立:

X <: Y ⇒ (Z → X) <: (Z → Y)
X <: Y ⇒ (Y → Z) <: (X → Z)

也就是说,函数类型构造函数对于结果类型(数据源)是协变的,对于参数类型(数据接收器)是逆变的。这是一个基本事实,你或多或少不能做任何太有创意的事情,比如颠倒箭头的方向。当然,您始终可以使用无方差代替协方差或逆变(大多数语言都这样做)。

对象类型可以用函数类型进行规范编码,因此这里也没有太多的自由度。每个类型参数代表数据源(协变)或数据接收器(逆变)或两者(变体)。如果它在一种语言中是健全的和逆变的,那么在另一种语言中它要么是逆变的,要么是不健全的。

我认为 Scala 在这方面非常接近理想的语言。您引用了一个看起来很像 Scala 的示例,因此您很可能熟悉该语言。我想知道为什么你认为它的类型系统只在某些情况下才能很好地工作。其他情况是什么?

每个有抱负的语言设计师都应该阅读的一部理论著作是 Luca Cardelli 的“A Theory of Objects”。

于 2011-07-18T13:38:51.557 回答