Start by not showing up in the package object and the disconnected class class:
package rabbit { trait TC object Test extends App { implicit object testInstance1 extends TC { override def toString = "test1" } { implicit object testInstance2 extends TC { override def toString = "test2" } println(implicitly[TC]) } } }
Scalac looks for any objects in visibility, finds testInstance1
and testInstance2
. The fact that one is in a tougher region makes sense only if they have the same name - the usual shadow copy rules apply. We chose different names, and there is not implied more specific than the other, therefore ambiguity is reported.
Let's try another example: this time we will play an implicit local scope against an object in the package.
package rabbit { object `package` { implicit object packageInstance extends TC { override def toString = "package" } } trait TC object Test extends App { { implicit object testInstance2 extends TC { override def toString = "test2" } println(implicitly[TC]) } } }
What's going on here? The first phase of an implicit search, as before, considers all non-attendances in the scope of the call site. In this case, we have testInstance2
and packageInstance
. They are ambiguous, but before reporting this error, the second phase starts and looks for the implicit TC
volume.
But what is there in the implicit realm? TC
doesn't even have a companion object? We need to consider the exact definition here in 7.2 of the Scala reference.
An implicit domain of type T consists of all related modules (ยง5.4) of classes associated with implicit type parameters. Here we say that a class C is associated with a type T if it is a base class (ยง 5.1.2) of some part T.
Type T
Parts:
- if
T
is a composite type T1 with ... with Tn
, the union of the parts T1, ..., Tn
, as well as T
, - if
T
is a parameterized type of S[T1, ..., Tn]
, the union of the parts S
and T1,...,Tn
, - if
T
is a singleton type p.type
, parts of type p
, - if
T
is a projection of type S#U
, part S
, and also T
, - in all other cases, just
T
We are looking for rabbit.TC
. From the point of view of the type system, this is an abbreviation for: rabbit.type#TC
, where rabbit.type
is a type representing the package as if it were a regular object. By invoking rule 4, we get the parts of TC
and p.type
.
So what does this mean? Just the implicit members in the package object are also part of the implicit volume!
In the above example, this gives us an unambiguous choice in the second phase of the implicit search.
Other examples can be explained in a similar way.
In short:
- Implicit search continues in two stages. The usual import and shadow copy rules define a list of candidates.
- Implicit members in a package enclosing object can also be in scope if you use nested packages .
- If there are several candidates, static overload rules are used to see if there is a winner. By adding a tiebreak, the compiler prefers one implicit over another, defined in the superclass of the first.
- If the first phase fails, then implicit coverage is considered in the same way. (The difference is that implicit members from different satellites can have the same name without obscuring each other.)
- Implications in package objects from enclosing packages are also part of this implicit area.
UPDATE
In Scala 2.9.2, the behavior is different and incorrect.
package rabbit { trait TC object Test extends App { implicit object testInstance1 extends TC { override def toString = "test1" } { implicit object testInstance2 extends TC { override def toString = "test2" } // wrongly considered non-ambiguous in 2.9.2. The sub-class rule // incorrectly considers: // // isProperSubClassOrObject(value <local Test>, object Test) // isProperSubClassOrObject(value <local Test>, {object Test}.linkedClassOfClass) // isProperSubClassOrObject(value <local Test>, <none>) // (value <local Test>) isSubClass <none> // <notype> baseTypeIndex <none> >= 0 // 0 >= 0 // true // true // true // true // // 2.10.x correctly reports the ambiguity, since the fix for // // https://issues.scala-lang.org/browse/SI-5354?focusedCommentId=57914#comment-57914 // https://github.com/scala/scala/commit/6975b4888d // println(implicitly[TC]) } } }