Reputation: 3848
Considering the following case:
trait Companion {
implicit def str(a: A): String =
s"${this.getClass.getSimpleName}: %d" format a.n
}
class A(val n: Int)
object A extends Companion {}
class B(val x: Int, y: Int) extends A(y)
object B extends Companion {}
Now compiling the following code will trigger a diverging implicit error:
val b = new B(5, 2)
val s: String = b
println(s)
because both object A and AA are in the default implicit scope of AA. This is clearly defective: the class AA is more 'exact' than trait A, henceforth it's implicit scope should have higher precedence. Unfortunately, because objects cannot inherit from each other, there is no way to declare this.
So my question is: what is the best way to achieve this, without resorting to non-default implicit scope?
Upvotes: 3
Views: 103
Reputation: 51683
Now compiling the following code will trigger a diverging implicit error:
It's not "diverging implicit error", it's ambiguity, implicit ambiguity and implicit divergence are different.
Implicits regarding type X
should go to companion object of X
. So if this is an implicit conversion between A
and String
it should go to companion object of A
. But then you have issue with .getSimpleName
.
Common approach is parametrizing parent trait for companion objects (as @MarioGalic advises):
If you don't want to make T
a type parameter you can make it a type member
trait Companion {
type T <: A
implicit def str(a: T): String = s"${this.getClass.getSimpleName}: %d" format a.n
}
class A(val n: Int)
object A extends Companion {
type T = A
}
class B(val x: Int, y: Int) extends A(y)
object B extends Companion {
type T = B
}
Also you can try to override implicit
trait Companion {
implicit def str(a: A): String = s"${this.getClass.getSimpleName}: %d" format a.n
}
class A(val n: Int)
object A extends Companion
class B(val x: Int, y: Int) extends A(y)
object B extends Companion {
override implicit def str(a: A): String = super.str(a)
}
or
trait LowPriorityCompanion {
implicit def str(a: A): String = s"${this.getClass.getSimpleName}: %d" format a.n
}
trait Companion extends LowPriorityCompanion {
override implicit def str(a: A): String = super.str(a)
}
class A(val n: Int)
object A extends LowPriorityCompanion
class B(val x: Int, y: Int) extends A(y)
object B extends Companion
Upvotes: 2