underscoreio/essential-scala

Description of Implicit scope might be wrong

Closed this issue · 2 comments

Section 7.2.1, Implicit Scope in Essential Scala has the following snippet:

The implicit scope also includes the companion objects of types involved in the method call with the implicit
parameter. Let’s look at sorted for example. The signature for sorted, defined on List[A], is:
sorted[B >: A](implicit ord: math.Ordering[B]): List[A]
The compiler will look in the following places for Ordering instances:
• the companion object of List;
• the companion object of Ordering; and
• the companion object of the type B, which is the type of elements in the list or any superclass.

I do not think listing "the companion object of List;" as part of the implicit scope, in this case, is accurate.

The first reason why I said this was I looked into the companion object of List and I did not see any implicit Ordering defined in there.

The second reason was I tried to validate this by using the following code:

class Box[A](val value:A) {
  def sorted(implicit ordering: Ordering[A]) = println(ordering.compare(value,value))
}
object Box {
  implicit val mine = new Ordering[Int] {
    override def compare(x: Int, y: Int) = 42
  }
}

// If companion object of Box is part of the implicit scope then 42 should be printed
// But 0 is printed meaning its the implicit in Ordering that is picked up
println((new Box(1)).sorted)

but when I moved the implicit out to the local scope, mine implicit value get picked up:

class Box[A](val value:A) {
  def sorted(implicit ordering: Ordering[A]) = println(ordering.compare(value,value))
}
object Box {
//  implicit val mine = new Ordering[Int] {
//    override def compare(x: Int, y: Int) = 42
//  }
}

// implicit now in local scope and 42 is printed
// proving that with the type signature, the companion object of Box
// and hence List would not be looked into
implicit val mine = new Ordering[Int] {
  override def compare(x: Int, y: Int) = 42
}

println((new Box(1)).sorted)

I became suspicious of the accuracy of the statement when it did not conform to the heuristics I have developed to reason about implicits and implicit resolution.

Which is to see the implicit application as a Function application, which can take the given type, or nothing, to create the required type needed to prevent a compilation error.

And that the implicit scope is the scope of the type you will see in this function signature including their associated types.

I blogged about this here (http://www.geekabyte.io/2017/12/implicit-scope-and-implicit-resolution.html you can check it out for more explicit description.

In case of sorted, the function signature that described the implicit resolution will be [Nothing => Ordering[B]] since nothing was given, but an Ordering[B] is needed to prevent the compilation error

Hence the places that the Scala compiler would look into will be the local scope, then the implicit scope of the associated types...and in this case, the associated types are Ordering and B, hence the companion object of Ordering and whatever Type B is would be searched...and List would not be included.

Would be nice if you can review this section in the book and confirm if my suspicion is accurate. It would also help validate my heuristic (or perhaps modify it, if it ends up being wrong)

Yes you're right. List shouldn't be in the list of search locations. Thanks for the spot. Will fix!

Fixed in 4c698f1.