作者macbuntu (邀怪)
看板PLT
標題[問題] Scala 的 Covariant/Contravariant/Invariant
時間Sun Mar 15 01:20:03 2009
看到 godfat 大大在 Java 版提到 Scala 的 Variant 方式,
覺得很有趣, 上網找了 Scala 的資料看了一下,
發現 Scala 的 type variance 選擇還真多, 三種 variance 方法都允許,
而且是可以直接應用在 type parameter 上面.
但是仔細想想, 就開始懷疑某些 variance 在實務上的實用性,
甚至有時候會干擾原先 OO 的語意?
譬如從 Covariant 開始, 如果定義 List[+T],
則只要 A 是 subclass of B (這裡用 A < B 表示), 則 List[A] < List[B].
從 OO 的觀點, 這表示 List[A] 可以被當成 List[B] 用在所有 List[B] 出現的地方.
但實際上卻不然, List[B].add(B) 就不該能用 List[A].add(B) 才對.
Java 的 array 就是 covariant, 變得會允許下面這種不正當的操作:
String[] s = new String[5];
Object[] o = s; // array is covariant so this is allowed
o[3] = new Object();
String name = s[3]; // throws ArrayStoreException !
反過來, Contravariant 就更令我納悶了, 如果定義 List[-T],
表示當 B < A, 則 List[A] < List[B]... that makes my head spin...
所以如果用 Java 的 pseudo code 來表示, 變成:
Object[] o = new Object[5];
String[] s = o; // this is allowed if contravariant
真的會有好的理由在實務上需要這樣的 variant 嗎? 在我自己的感覺,
這種功能造成的問題可能比解決的問題還多...
最後 Invariant, 這就很直接了, 如果定義 List[T],
則不論 A < B 或 B < A, List[A] 跟 List[B] 互相完全沒關係,
這最保守, 最不會干擾 OO 的語意, 但是也最不靈活.
Java 的 type parameter 就選擇了這種, 只是加上了一些 bounded type 定義
讓它稍微靈活一點, 但基本上還是 Invariant.
或許 template based polymorphism 本質上就跟 class based polymorphism 不一樣,
所以湊在一起就是會有衝突的地方吧? 感覺上 Java 比較保守,
盡量維持 class based typing 的一致性, 而 Scala 就蠻大膽的,
全部放進去看看大家怎麼用 (functional programming? anyone? ...)
哈, 突然想到一句話: "High explosives, handle with care."
--
※ 發信站: 批踢踢實業坊(ptt.cc)
◆ From: 118.165.166.80
1F:推 godfat:久違的心得好感動啊... 晚了明日再回 @@ 03/15 01:48
2F:推 jaiyalas:簡直感動到痛哭流涕呀 ~ 03/17 09:44