若 c' subclass c 且 o': InstanceTypeOf(c'),則 o': InstanceTypeOf(c)。拆解為:
a: A, A <: B ⇒ a: B(子類型判斷唯一標準)。InstanceTypeOf(c') <: InstanceTypeOf(c) ⇔ c' subclass c。所有 OO 語言支持 Subsumption;大多數不區分子類化與子類型,少數新語言分離二者(類似 C++ 私有繼承但更豐富)。
procedure f(x: InstanceTypeOf(cell)) {
x.set(3); // 調用 cell.set 還是 reCell.set?
}
f(myReCell); // myReCell: InstanceTypeOf(reCell)
cell.set)。reCell.set),需對象內部狀態不變(無對象切片)。C++ 虛函數表實現動態分派,指針調整可能發生但語義保持對象身份不變。
Subsumption 導致靜態類型信息遺失:將 MyObject 視為 Object 只能訪問基類接口。純粹派主張僅用動態分派操作遺失成員,但現實語言提供 RTTI:
dynamic_castinstanceofdynamic_cast/instanceof 站點,編譯器無法協助,缺乏擴展性。運行開銷非核心問題,方法論缺陷才是關鍵。類型系統演進多源於避免 RTTI(如 Self 類型、協變返回類型)。
| 構造 | 類型參數位置 | 變化性 | 規則 |
|---|---|---|---|
| Pair A×B | 返回類型 | 協變 | A' <: A ⇒ A'×B <: A×B |
| Function B→A | 參數類型 | 反協變 | B' <: B ⇒ (B→A) <: (B'→A) |
| Function B→A | 返回類型 | 協變 | A' <: A ⇒ (B→A') <: (B→A) |
| Function A→A | 參數+返回 | 不變 | 無子類型關係 |
可變容器(如 setA(A))導致不變性,函數式不可變數據結構天然協變。
覆寫方法允許:
class c {
method m(x: A): B ...
}
subclass c' of c {
method m(x: A'): B' ... // 合法若 A <: A' 且 B' <: B
}
此規則保證類型安全:調用者按父類簽名傳參,子類方法能處理更寬參數;調用者期望父類返回類型,子類返回更具體類型符合預期。