同じ名前のメソッドを持つクラスに対するimplicit defを2つ定義してimportした場合のコンパイルエラーがScala2.9と2.10で異なる件
「同じ名前のimplicit defを2つ定義してimportした場合の挙動がScala2.9と2.10で異なる件 - xuwei-k's blog」みて思い出したので確認してみた。
Scala 2.9.1 + scalaz 6.0.3で下のようなコードを書いてコンパイルすると "reassignment to val" エラーになる。
import scalaz._; import Scalaz._ object IsWriterMAOrMAB { def main(args: Array[String]) { writer("foo", 1) >>= (n => writer("bar", n)) } }
[error] /tmp/ScalaSample/src/main/scala/IsWriterMAOrMAB.scala:5: reassignment to val [error] writer("foo", 1) >>= (n => writer("bar", n)) [error] ^ [error] one error found [error] {file:/tmp/ScalaSample/}root/compile:compile: Compilation failed
implicit conversionsの適用時に曖昧でエラーが出た後、メソッド名が「=」で終わっているので代入演算子として再解釈しようとして"reassignment to val"というエラーになる模様。
scalazを使わず再現するコードを書くとこんな感じ。
object AmbiguousImplicitsSample { implicit def foo(n: Int) = new { def #=(m: Int) = m == n } implicit def bar(n: Int) = new { def #=(m: Int) = m == n } def main(args: Array[String]) { val i = 1 println(i #= 1) } }
メソッド内の処理の内容は特に関係ないです。
Scala 2.9.1でコンパイルすると……
[error] /tmp/ScalaSample/src/main/scala/AmbiguousImplicitsSample.scala:11: reassignment to val [error] println(i #= 1) [error] ^ [error] one error found [error] (compile:compile) Compilation failed
メソッド名を「eq」や「=#=」などに変えると、ちゃんと「曖昧なのでimplicit conversionsを適用しませんでした」エラーになる。
[error] /tmp/ScalaSample/src/main/scala/AmbiguousImplicitsSample.scala:11: type mismatch; [error] found : i.type (with underlying type Int) [error] required: ?{val =#=(x$1: ?>: Int(1) <: Any): ?} [error] Note that implicit conversions are not applicable because they are ambiguous: [error] both method foo in object AmbiguousImplicitsSample of type (n: Int)java.lang.Object{def =#=(m: Int): Boolean} [error] and method bar in object AmbiguousImplicitsSample of type (n: Int)java.lang.Object{def =#=(m: Int): Boolean} [error] are possible conversion functions from i.type to ?{val =#=(x$1: ?>: Int(1) <: Any): ?} [error] println(i =#= 1) [error] ^ [error] one error found [error] (compile:compile) Compilation failed
[error] /tmp/ScalaSample/src/main/scala/AmbiguousImplicitsSample.scala:11: type mismatch; [error] found : i.type (with underlying type Int) [error] required: ?{def #=(x$1: ? >: Int(1)): ?} [error] Note that implicit conversions are not applicable because they are ambiguous: [error] both method foo in object AmbiguousImplicitsSample of type (n: Int)AnyRef{def #=(m: Int): Boolean} [error] and method bar in object AmbiguousImplicitsSample of type (n: Int)AnyRef{def #=(m: Int): Boolean} [error] are possible conversion functions from i.type to ?{def #=(x$1: ? >: Int(1)): ?} [error] println(i #= 1) [error] ^ [error] /tmp/ScalaSample/src/main/scala/AmbiguousImplicitsSample.scala:11: value #= is not a member of Int [error] println(i #= 1) [error] ^ [error] two errors found [error] (compile:compile) Compilation failed
implicit conversionsの適用時に曖昧でエラーが出た後、「=」で終わるメソッド名でも、代入演算子として再解釈せずにエラーになりコンパイルが停止する模様。
これは多分改善されているのだと思う。まあどっちにしてもコンパイルエラーなので特に困ることはないと思うけど。