1
votes

Why is the following (toy) sample compiled in Scala without any problem, and what is the rule used for deciding which implicit conversion to chose?

object test1 {
  class MyInt(val v: Int) {
    def +(other: MyInt) = new MyInt(v + other.v)
    override def toString = v.toString
  }
  class MyIntMod10(vparam: Int) {
    val v = vparam % 10;
    def +(other: MyIntMod10) = new MyIntMod10(v + other.v)
    override def toString = v.toString
  }

  val a = new MyInt(7);                           //> a  : test1.MyInt = 7
  val b = new MyIntMod10(7);                      //> b  : test1.MyIntMod10 = 7
  implicit def toIntMod10(x: MyInt) = new MyIntMod10(x.v)
                                                  //> toIntMod10: (a: test1.MyInt)test1.MyIntMod10
  val c1 = a + b                                  //> c1  : test1.MyIntMod10 = 4
  val c2 = b + a                                  //> c2  : test1.MyIntMod10 = 4

  implicit def toInt(x: MyIntMod10) = new MyInt(x.v) //> toInt: (b: test1.MyIntMod10)test1.MyInt
  val c3 = a + b                                  //> c3  : test1.MyInt = 14
  val c4 = b + a                                  //> c4  : test1.MyIntMod10 = 4
}

I expected the two last lines to produce compile-time error because of ambiguity, but they don't. (As far as I know, the fact that the values of c1 and c3 are different, directly shows the ambiguity in calculating c3! please correct me if I'm wrong.)

I know that in current versions of Scala, some ambiguous implicit calls are resolved by the compiler, but I can't see how the given sample code is one of those special cases!

1

1 Answers

1
votes

In the case of the lines setting c1 and c3, the + method called is the one defined on MyInt. In these cases the compiler attempts first to convert the argument to the + method (b) into a MyInt. Likewise, for c2 and c4, the + method called is the one defined on MyIntMod10, so the compiler looks to convert a into a MyIntMod10.

This works fine for c2, c3, and c4 where an appropriate implicit is available.

For the case of c1, there is no implicit (at that point) to convert b into a MyInt, so it then looks for a way to convert a to something with a + method that can take a MyIntMod10 as a parameter - and thus finds the implicit conversion to MyIntMod10 to apply to a, converting it into a MyIntMod10 as you have observed.