Skip to content

定义Definition

子类型

施工中 · 内容逐步修订

Subtyping

允许某类型值在期望其上界类型的位置使用的可替代关系。

形式陈述 ​

子类型关系 S<:T 表示每个 S 型值都可在期望 T 型值的位置安全使用。类型系统通常包含自反性、传递性和 subsumption 规则

Γ⊢t:SS<:TΓ⊢t:T.

因此子类型通常首先是预序,而非语法类型上的偏序:互为子类型的两个类型未必字面相同;按 S≡T⟺S<:T∧T<:S 取商后,才可把等价类视为反对称的偏序。

函数类型满足参数逆变、结果协变:

S2<:S1T1<:T2S1→T1<:S2→T2.

不可变积与记录通常按分量协变;记录还可有宽度子类型。含可写位置的引用类型一般不能简单协变,否则会破坏类型安全。

直觉

子类型不是“结构看起来像”或“类继承了谁”,而是上下文中的可替代性承诺。函数参数逆变最容易反直觉:一个能处理所有动物的函数当然能放到只会收到猫的位置,而只处理猫的函数不能冒充能处理所有动物的函数。结果则相反,返回更具体的猫可安全当作返回动物。定义中的方向由谁提供、谁消费数据决定,而不是由语法箭头机械决定。

渐进类型的一致性关系回答已知信息是否冲突:Int 与未知类型一致,未知类型又与 Bool 一致,但 Int 与 Bool 不一致,因此它不具备子类型的传递性。描述注解信息多少的精度关系也不同于可替代性;其函数参数和结果都沿相同的信息遗忘方向变化。

例子与边界

结构记录中,若只读字段采用宽度子类型,则 {x:Int,y:Int}<:{x:Int}:需要x的代码可以忽略额外的y。若还要求修改一个字段后在结果类型中保留其余字段,可用行多态让输入输出共享同一个未知行;单独的闭合 {x:Int}→{x:Int}签名不会记录y仍存在。

函数 Animal→Cat 可作为 Cat→Animal 使用,因为它接受范围更广、返回结果更具体。

边界是可变引用。若假设 Ref Cat <: Ref Animal,代码可通过 Ref Animal 写入一只狗,原持有者随后从 Ref Cat 读出狗,类型承诺被破坏;因此可读写引用通常不变。名义继承也不自动等于行为子类型,违反方法契约的子类不能仅凭语法继承获得可靠替代性。

推论与应用

子类型支撑面向对象接口、记录扩展、数值层次和 API 演化。所有权与借用还会把生命周期包含解释成引用可缩短使用区间的 region subtyping;独占 reborrow 与可变引用的 variance 另有别名约束,不能从普通协变机械推出。算法类型检查需要决定 S<:T,复杂系统还需处理交、并、递归类型与有界量化。

在只有基础类型、Top、箭头和只读记录的可观察递归图中,循环子类型判定可用有限有序节点对终止:方法参数生成反向义务,结果和字段保持原方向。重复对只登记本次待检查假设,整份义务封闭后才发布成功;无守卫传递规则不能直接加入结构最大不动点,否则错误判断也能用无限自引获得接受。

它与参数多态是不同复用机制:前者允许较具体值向上转换,后者要求同一代码对所有类型参数统一工作。类型判断通过 subsumption 接纳子类型,而类型安全约束每条子类型规则必须保持运行时行为。

参考资料
  • Benjamin C. Pierce, Types and Programming Languages, MIT Press, 2002,Chs. 15–18, subtyping, records, and variants。
  • Robert Harper, Practical Foundations for Programming Languages, 2nd ed., Cambridge University Press, 2016,Chs. 21–24, subtyping and variance。
关系图谱11 个相邻概念 · 3 类关系

拖动节点调整位置。

显示关系

显示:依赖

  1. 前置三跳
  2. 前置二跳
  3. 前置一跳
  4. 当前条目
  5. 后续一跳
  6. 后续二跳
  7. 后续三跳
文字版关系按与当前条目的最短距离分组
类型化关系

被这些条目使用

并列辨析