作者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