AlphaGeek
AlphaGeek

Reputation: 392

What are scala's rules for resolving conflicting implicit values

Given the following code:

/**
  * Created by danap on 12/8/15.
  */
object ImplicitTest {
  trait EC {
    override def toString : String = s"EC"
  }

  trait DEC extends EC {
    def sub : EC
    override def toString : String = s"DEC - $sub"
  }

  def usesEC(implicit ec : EC) = ec.toString

  class B(implicit val dec: DEC) {
    def whichEC = usesEC
  }

  class C(implicit val dec: DEC) {
    implicit val _ec = dec.sub

    def whichEC = usesEC
    def whichECExplicit = usesEC(_ec)
  }

  def main(args:Array[String]): Unit = {

    implicit val dec : DEC = new DEC {
      val sub = new EC {}
    }

    val b = new B
    val c = new C

    println(s"b class = ${b.whichEC}")
    println(s"c class = ${c.whichEC}")
    println(s"c class = ${c.whichECExplicit}")
  }
}

The output for scala 2.11 is:

b class = DEC - EC
c class = DEC - EC
c class = EC

I expected it to be:

b class = DEC - EC
c class = EC
c class = EC

Because the implicit val _ec is declared "closer" to the call to usesEC in whichEC. Why does this happen? Also,how I might be able to force _ec to be used implicitly in C.whichEC?

Upvotes: 2

Views: 938

Answers (1)

0__
0__

Reputation: 67280

Sub-type wins:

class Super             { override def toString = "Super" }
class Sub extends Super { override def toString = "Sub"   }

// does not compile - ambiguous
object Test1 {
  implicit val s1 = new Super
  implicit val s2 = new Super

  println(implicitly[Super])
}

// does not compile - ambiguous
object Test2 {
  implicit val s1 = new Sub
  implicit val s2 = new Sub

  println(implicitly[Super])
}

object Test3 {
  implicit val s1 = new Super
  implicit val s2 = new Sub

  println(implicitly[Super])
}

Test3 // 'Sub'

The rules for resolution of implicit parameters are defined in §7.2 of the Scala Language Specification:

If there are several eligible arguments which match the implicit parameter's type, a most specific one will be chosen using the rules of static overloading resolution.

This links to §6.26.3 which deals with type inference. Here a type A <: B gives the alternative sub-class A a relative weight of 1 over the alternative super-class B, making A more specific than B.


In general, as the comment suggests, you should avoid bringing multiple unqualified members (prefix-less, i.e. implicit values that are found in default locations for example through companion objects) into scope.

Upvotes: 4

Related Questions