作者macbuntu (邀怪)
看板PLT
标题Re: [问题] Scala 的 Covariant/Contravariant/Inv …
时间Mon Mar 16 00:34:09 2009
※ 引述《godfat (godfat 真常)》之铭言:
: 可以改看 Function 的例子,那就真的是有 contravariant parameter type 了。
: http://www.scala-lang.org/docu/files/api/scala/Function1.html
: trait Function1[-T1, +R]
: extends AnyRef
: 其中 -T1 是第一个 parameter, +R 是其 return type.
今天再玩了一下 Scala, 发现 Scala 的 variant 并没有我原先想的那麽天真,
它有个很聪明的设计, 靠 compile time type checking 把不正当的型别使用挡掉,
所以我原先想的那些 covariant 跟 contravariant 的问题其实在 Scala 都不会发生.
真强... 譬如说:
class Foo[
T] (init:
T) {
private var x:
T = init
def get:
T = { x }
def set(x:
T) = { this.x = x }
}
这里定义 Class Foo 用 Invariant type parameter, 所以没问题,
不论 A < B 或 B < A, Foo[A] 跟 Foo[B] 都没关系.
但如果换成用 +T 的 covariant 来定义 Foo:
class Foo[
+T] (init:
T) {
private var
x:T = init
def get:
T = { x }
def set(
x:T) = { this.x = x }
}
// convariant type T occurs in contravariant position ....
Scala 的 compiler 就会把上面红色的地方标成错误而不会 compile 成功,
原因是 Scala 会根据型别出现的位置来决定该位置所能允许的 variant 种类,
所以像 function argument type 是 contravariant 而 return type 是 covariant
这类的规则直接定义成语言的一部分, 再将 programmer 宣告的 +/- variant 方式
跟这些位置作比对, 符合才放行, 从根本上解决了 variant 跟 OO 的冲突问题.
觉得这种方法挺漂亮的, 其实可以加到 Java 的语法里又不会造成冲突.
以现在的 Java 来说:
interface
A<T> {
public
T get();
}
class B {
static void func(
A<Object> a) { .... }
}
A<String> obj = /* new something */;
B.func(
obj); // compile time error, A<String> is not an A<Object>
这里 Java compiler 不允许, 但是仔细看 A<T> 的 T 其实只用在 return type,
把 A<String> 当作 A<Object> 使用一点问题也没有. 如果把 Scala 的设计加进去:
interface
A<+T> {
public
T get(); // OK
}
interface
B<+T> {
public
T get(); // OK
public void set(
T t); // compile time error
}
interface
C<-T> {
public void set(
T t); // OK
}
interface
D<-T> {
public
T get(); // compile time error
public void set(
T t); // OK
}
interface
E<T> {
public
T get(); // OK
public void set(
T t); // OK
}
靠 compiler 来检查所有定义为 +T (covariant) 的型别只能用在 return type,
而所有 -T (contravariant) 的型别只能用在 arguments type,
如果同时用在两个地方, 或是 public field type, 就一定得指定成 T (invariant),
这样就皆大欢喜了.
或者可以连 +/- 符号都不必放, 直接把上面想法当成 implicit sementic rule,
compiler 根据 T 出现的位置来认定它的 variant 能力, 然後才决定
Foo<String> 跟 Foo<Object> 之间有没有继承的关系, 这样连 syntax 都不必改了.
话说回来, 能让 programmer 明确指定意图, 再让 compiler 检查正确性,
可能还是比 implicit rule 好吧.
印象中现在 Java 1.5 generics type 的设计就是出自於设计 Scala 的同一人?
不知他当时没把这个放入 Java 中是有什麽原因? 还是当初还没有这个点子...
: 虽然说冷了很久很久了(PLT 板也是),不过 function programming 是
: 最热门的话题哟。 http://flolac.iis.sinica.edu.tw/lambdawan/forum/22
我只有很以前有用过 Lisp 而已, 现在只剩一个感觉就是写起来像在玩头脑体操 :P
看论文好像常常会看到 Haskell, 还真该找时间学学...
--
※ 发信站: 批踢踢实业坊(ptt.cc)
◆ From: 114.32.132.21