« Home

Structural Interface 的設計限制 [G9M2]

前幾日跟朋友探討他新寫的程式語言的特性設計時,討論到他希望 interface 與 record 都是 structural 時,發現了一些小小的設計限制,所以在這裡紀錄下來。

Go 的兩個特性 [local-0]

  • struct 是 nominal:兩個欄位相同的 struct 依然是不同型別
  • interface 是 structural:只看 method set 自動匹配,不需顯式宣告

兩者看起來是各自獨立的設計選擇,然而

如果 struct 是 structural [local-1]

interface Hello { hello() }
type T = struct {}
func (t *T) hello() { ... }
  1. structural rule 下 T 只是形狀 {} 的一個參考用標籤,並不會被型別系統認知到
  2. structural subtyping 下,所有 record 在結構上都包含空欄位集,所以全部都得到了 hello() 的實現
  3. 結合 structural interface 認為有方法就算實作,就等於所有 record 類型都實現了 Hello
  4. 若其他類型也各自定義 hello(),要使用哪個就由 method resolution 演算法決定,這個結果通常是非常不穩定的(更不用說這裡還需要底下實現紀錄是哪個 record 實現了 method,與類型系統設計不匹配,讓 resolution 的結果更難被理解與信任)

所以 Go 選擇 nominal struct 是出於真正的約束所限,一但選擇 structural interface 就需要對其他部分做出讓步。