什么时候发生类型擦除?

时间:2012-02-27 20:47:04

标签: scala mixins type-erasure

scala的语法很有前途。我认为原来scala不仅仅是舒适的java并且可以引入全新的编程范例,但语法允许的许多功能在语义上是不正确的。所以我开始寻找scala限制和黑客来消除它们。虽然我只是编写一个测试项目,以适应其他观点的scala方式和模式。

主要障碍是从jvm实现继承的类型擦除。我可以写一篇名为“十种漂亮的图案,类型擦除已毁了”的小文章。有人说,类型擦除会污染泛型,但我偶然发现了mixins中的类型擦除。我认为scala中的mixin实现存在问题。

序言

trait T1
trait T2

trait B1 {
  def typeMe(x:T1){}
}

使用mixins打破代码

trait B2 extends B1 {
  def typeMe(x:T1 with T2) {}
}

使用mixin声明为单独特征的工作代码

trait T3 extends T1 with T2
trait B3 extends B1 {
  def typeMe(x:T3) {}
}

错误是:

error: name clash between defined and inherited member:
method typeMe:(x: T1 with T2)Unit and
method typeMe:(x: T1)Unit in trait B1
have same type after erasure: (x: $line12.$read#$iw#$iw#T1)Unit
    def typeMe(x:T1 with T2)

有哪些最佳解决方法?引入新特性是一种冗长(特别是对于大型混合链)并导致类型不兼容。添加模拟隐式参数也不是银弹,因为它增加了开销。


更新

我很抱歉,我问了一个错误的问题。我更感兴趣的是所描述错误的性质,而不是其解决方法。类型擦除在哪里发生?我认为代码中没有泛型被认为是类型擦除源。编译器行为背后的机制是什么?

1 个答案:

答案 0 :(得分:3)

你想要做的事情有几个问题。

首先,类型擦除发生时并不重要。这是因为类型擦除的概念是,无论是在计算之前还是之后擦除类型,结果都应该相同。对于JVM语言,一些擦除发生在编译时,iinm。

其次,您的“工作”代码实际上并不像您认为的那样工作。这需要对子类型,协方差和逆变量有一点了解。 (Foo <: Bar表示“Foo是Bar的子类型”,或者非正式地表示“Foo比Bar更具体”)。函数在输入中是逆变的,在输出中是协变的,这意味着仅当A => B <: W => VW <: A时函数B <: V

现在考虑一下你的职能:

B1.typeMe(x:T1)
B3.typeMe(x:T3)

B3.typeMe的输入为T3,而B1.typeMe的输入类型为T1。但是,T3 <: T1(T3 比T1更具体),因此B3.typeMe 的类型不能是{{1>类型的子类型}}。相反,它们被简单地视为单独的功能,有时会发生一些令人毛骨悚然的无声阴影。老实说,这可能会发出错误或至少发出警告。值得庆幸的是,另一个版本确实如此。