子類型

一种类型多态的形式

編程語言理論中,子類型動名詞,英語:subtyping)是一種類型多態的形式。這種形式下,子類型名詞,英語:subtype)可以替換另一種相關的數據類型超類型,英語:supertype)。也就是說,針對超類型元素進行操作的子程序、函數等程序元素,也可以操作相應的子類型。如果 S 是 T 的子類型,這種子類型關係通常寫作 S <: T,意思是在任何需要使用 T 類型對象的環境中,都可以安全地使用 S 類型的對象。子類型的準確語義取決於具體的編程語言中「X 環境中,可以安全地使用 Y」的意義。編程語言的類型系統定義了各自不同的子類型關係。

由於子類型關係的存在,某個對象可能同時屬於多種類型,因此,子類型(英語:subtyping)是一種類型多態的形式,也被稱作子類型多態(英語:subtype polymorphism)或者包含多態(英語:inclusion polymorphism)。在面向對象程序設計中,多態一般僅指這裡所說的「子類型多態」,而「參數多態」則一般被稱作泛型編程

子類型與面向對象語言中(類或對象)的繼承是兩個概念。子類型反映了類型(即面向對象中的接口)之間的關係;而繼承反映了一類對象可以從另一類對象創造出來,是語言特性的實現。因此,子類型也稱接口繼承;繼承稱作實現繼承

例子

 
子類型的例子:鳥

右圖中給出了子類型的一個簡單實際例子。一般性對象「鳥」(或超類型)引發了三個派生對象(或子類型)「鴨子」、「杜鵑」和「鴕鳥」。每個都以自己的方式改變了基本的「鳥」的概念,但仍繼承了很多「鳥」的特徵。一個數據對象可以被聲名為這四種類型中任何一個。這個圖中使用了 UML 符號,箭頭指示方向和超類型和它的子類型之間的聯繫。

在多數基於類的面向對象編程語言中,子類引出子類型:如果 AB 的子類,則類 A 的實例可以用在期望類 B 的實例的任何上下文中;所以我們稱 AB 的子類型。一個結論就是聲明有類型 B 的任何變量或形式參數在運行時間可以持有類 A 的一個值;在這種情況下很多面向對象編程者會聲稱 B 是這個變量的「靜態類型」而 A 是它的「動態類型」。這個規則的例外包括 C++語言中的私有繼承(它不建立子類型),和 Eiffel 語言中在派生類型上特定運算,在其中繼承自基類的特徵可以用違反子類型規則的方式去除或修改。

另一個例子是可以允許整數值被用在期望浮點數值的地方,或可以定義包含整數和實數二者的一個類型 number 的語言。在第一種情況下,整數類型將是浮點數類型的子類型;在第二種情況下,這兩個類型都是 number 的子類型而相互之間無子類型關係。

編程者可利用子類型來以比沒有它更抽象的方式來寫代碼。考慮下面的例子:

function max (x as number, y as number) is
  if x < y then
    return y
  else
    return x
end

如果整數和實數都是 number 的子類型,則二者任何類型都可以傳遞給這個函數。為此,子類型經常被認為是一種形式的多態性。上述例子也可以比較於 C++ 語言的模板

類型論中,子類型關係經常寫為 <:,有着 A<:B 意味着 AB 的子類型。在類型論中子類型可用如下事實來特徵化,如果 A<:B,類型 A 的任何表達式也可被給予類型 B;立法這個特徵化的形式類型規則叫做「包容」規則。

子類型方案

類型理論研究者區分兩類類型系統:

上面描述的基於類的面向對象子類型描述是名義的;面向對象的結構子類型規則可以聲稱,如果類型 A 的一個對象能處理類型 B 的對象能處理的所有消息(就是說,如果它們定義都同樣的方法),則 AB 的子類型,不管二者任何一個是否從繼承自其他對象。不是對象類型的類型的健壯的結構子類型規則也是周知的。

帶有子類型的編程語言實現可分為兩大類:

  • 如果 A<:B,類型 A 的任何值的表示也表示類型 B 的相同值,則為「包含實現」(inclusive implementation)。
  • 類型 A 的值可自動的轉換成類型 B 的值,則為「強制實現」( coercive implementation)。即類型強制轉換之意。

在面向對象語言中子類型所導致的子類型通常是包含的;聯繫整數和浮點數的子類型關係,它們有不同表示,通常是強制的。

在定義子類型關係的幾乎所有類型系統中,它是自反的(意味着對於任何類型 AA<:A)和傳遞的(意味着如果 A<:B 並且 B<:CA<:C)。這得到了在類型上的預序

記錄類型

記錄是命名的域(field)的集合。記錄類型(types of records)的子類型化包括寬度與深度兩種方式。

  • 寬度子類型化(width subtyping):給記錄增加更多的域。
  • 深度子類型化(depth subtyping):把超類型(supertype)的域替換為域的子類型。這僅能用於只讀(immutable)記錄。

函數類型

對於函數類型T1 → T2,其子類型為S1 → S2,則T1 <: S1且S2 <: T2。參數類型S1 → S2逆變,返回類型為協變

允許副作用的語言,如大部分面向對象語言,子類型化還不足以保證安全在另一個上下文中使用。行為子類型化要求保持不變[1]

可變引用(mutable reference)的子類型化類似於函數參數與返回值的處理。只寫引用是逆變的;只讀引用是協變的;可變引用是不變的。

類型強制

在強制子類型化系統(coercive subtyping system),子類型通過從子類型到超類型的隱式類型轉換函數得以定義。對於每個子類型關係 (S <: T),一個強制關係coerce: ST,使得任何對象s 為類型S,可以視作對象coerceST(s)具有類型T。類型強制函數可以複合:如果S <: TT <: U,難麼s 可以看作類型u在複合強制關係(coerceTUcoerceST)。類型到其自身的coerceTT同一函數idT

參考文獻

引用

  1. ^ Barbara Liskov, Jeannette Wing, A behavioral notion of subtyping頁面存檔備份,存於網際網路檔案館, ACM Transactions on Programming Languages and Systems (TOPLAS), Volume 16, Issue 6 (November 1994), pp. 1811 - 1841. An updated version appeared as CMU technical report: Liskov, Barbara; Wing, Jeannette. Behavioral Subtyping Using Invariants and Constraints (PS). July 1999 [2006-10-05]. (原始內容存檔於2012-08-30). 

來源

外部連結

參見

  • 派生類型是給出新類型但結構上同於最初類型的類型。依賴於類型系統,它可以是也可以不是子類型。
  • 基於類的編程有混淆了子類型和子類導致的問題的一個例子。