从编程语言的角度来看,子类型是什么意思?我听说“继承不是子类型化”。那么继承和子类型化之间有什么区别?
从编程语言的角度来看,子类型是什么意思?我听说“继承不是子类型化”。那么继承和子类型化之间有什么区别?
Answers:
[我还没有对面向对象类型系统的问题进行深入的思考,但是我会说出我所知道的使讨论继续进行。]
我们说如果所有A类型的值都可以在期望B类型的值的每个上下文中使用,则是B的子类型。或者,换句话说,A型值可以“伪装”为B型值。
如果这种伪装对类型检查没有问题,即在需要B类型值的地方插入类型值继续进行类型检查,我们将其称为“结构子类型化”。如果它不会引起任何行为问题,即,这种插入不会改变预期的行为,则我们将其称为“行为子类型化”。(“预期的行为”将必须单独形式化,并且许多行为概念都是可能的。)
结构子类型不能确保行为子类型,因为类型的结构可能出于偶然原因而匹配。但是,定义预期的行为并不容易。因此,许多编程语言都使用一个中间点,用户必须在其中声明哪种类型是其子类型。这称为“标称子类型化”。参见关于隐式与显式子类型的问题讨论这个问题。这个想法是程序员必须使用自己的独创性来确保所有声明的子类型的行为子类型。该语言无法提供任何帮助。但是,所有声明的子类型必须至少是结构子类型。否则,程序将无法输入检查。语言可以帮助确保这一点。(某些编程语言没有足够好的类型系统来确保在编译时做到这一点。如果是这样,则将在运行时检测到类型失败,或者可能会产生错误的结果。显然,这种类型的漏洞是不希望的。)
当在面向对象程序中定义子类时,通常会添加公开可见的字段(或方法)。在大多数编程语言中,此类子类被视为标称子类型。问题是它们是否也是结构亚型。如果不是这样,即编程语言允许人们声明不是结构子类型的标称子类型,那么在编程语言中将存在类型漏洞。
在简单的情况下,添加字段效果很好。超类的类型期望的字段少于子类的类型。因此,如果您插入需要sueprclass实例的子类实例,则该程序将只忽略提供的其他字段,并且不会出错。
但是,如果超类或子类具有使用与自身相同类型的参数或返回与自身相同类型的结果的方法,则会出现问题。然后,子类的接口类型不是超类的结构子类型。广泛使用的类型安全编程语言(例如Java)不允许此类子类。因此,它们限制了语言以获得类型安全性。据说Eiffel编程语言为了获得灵活性而牺牲了类型安全性。如果设计一个保留灵活性的强类型系统,则必须放弃子类产生子类型的原则。因此,论文的标题“继承不是子类型化”。作者提出了另一种高阶子类型的概念,该概念可以代替。金·布鲁斯(Kim Bruce)也有一个密切相关的提案,称为“匹配”,可以达到相同的效果。请参阅此演示文稿。Andrew Black 的立场文件也有帮助。
语义社区可能会因为很大程度上忽略了这个问题而有过错。传统上,我们将其视为实用的类型系统工程问题,几乎没有理论上的兴趣。如果不是这样,并且确实在该领域中有一些语义工作,我希望其他人会提及它们。