tribbloid
tribbloid

Reputation: 3838

In scala 2.13, why implicit scope of a companion object may sometimes be misaligned? How to correct it?

The following is a simple example that tests the implicit feature of the scala 2.13 compiler:

object OverridingScope {

  trait System {

    trait Handler[T]
  }

  object Sys1 extends System {

    object Handler {

      implicit def handle1: Handler[Int] = new Handler[Int] {}
    }

    implicit def handle2: Handler[Long] = new Handler[Long] {}
  }
}

According this article:

Where does Scala look for implicits?

The companion object of the trait Handler can be automatically imported as part of the implicit scope when type Handler[_] is used, the outer object Sys1 should be irrelevant. This means handle1 should be visible and handle2 should be hidden.

But the following test case shows the exact opposite:

class OverridingScope extends BaseSpec {

  import OverridingScope._

  it("implicits in companion is in scope") {

//    val hh = implicitly[Sys1.Handler[Int]]
    // Doesn't work
  }

  it("implicits in outer object is in scope") {

    val hh = implicitly[Sys1.Handler[Long]]
    // Should NOT work
  }
}

Considering that Handler is both a class & object name, the fact that handle1 doesn't work looks highly suspicious. Also, I've checked the full list of implicit import:

First look in current scope
Implicits defined in current scope
Explicit imports
wildcard imports
Same scope in other files
Now look at associated types in
Companion objects of a type
Implicit scope of an argument's type (2.9.1)
Implicit scope of type arguments (2.8.0)
Outer objects for nested types
Other dimensions

None of the above can explain why handle2 is in the scope. What could be the reasons?

BTW: For those who dismissed implicit as a important scala feature: Implicit is the only way to implement type class, and if you want to implement it with minimal boilerplate, sometimes the above pattern can be the only choice.

Upvotes: 0

Views: 262

Answers (1)

Jasper-M
Jasper-M

Reputation: 15086

Point 3 here explains that implicits/givens in prefixes of the type in question contribute to its implicit scope (in Scala 3 not if it's a package). So for the type Sys1.Handler[Long] implicits in Sys1 are in the implicit scope because Sys1 is a non-package prefix.

handle1 is not in the implicit scope because object Handler in object Sys1 is not the companion object of trait Handler in trait System.

Upvotes: 5

Related Questions