【发布时间】:2012-03-17 08:09:26
【问题描述】:
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)
可用的最佳解决方法是什么?引入新特性是冗长的(尤其是对于大型 mixin 链)并导致类型不兼容。添加模拟隐式参数也不是灵丹妙药,因为它会增加开销。
更新:
非常抱歉,我问错了问题。我对所描述错误的性质更感兴趣,而不是其解决方法。类型擦除发生在哪里?我在被认为是类型擦除源的代码中没有看到泛型。编译器行为背后的机制是什么?
【问题讨论】:
-
您可以考虑替代重载方法;以不同的方式命名它们或使用 typeclass 模式。
-
我希望你意识到在
B3中你不是从B1覆盖方法typeMe,而是重载它以获取子类型。虽然这是合法的,但这是一个坏主意,因为调用的方法将取决于局部变量的类型。即假设B3对象b3和T3对象t3、b3.typeMe(t3)和b3.typeMe(t3: T1)将调用不同的方法。
标签: scala mixins type-erasure