Suppose I've got a simple type class whose instances will give me a value of some type:
trait GiveMeJustA[X] { def apply(): X }
And I've got some instances:
case class Foo(s: String)
case class Bar(i: Int)
implicit object GiveMeJustAFoo extends GiveMeJustA[Foo] {
def apply() = Foo("foo")
}
implicit object GiveMeJustABar extends GiveMeJustA[Bar] {
def apply() = Bar(13)
}
Now I have a similar (but unrelated) type class that does the same thing but is covariant in its type parameter:
trait GiveMeA[+X] { def apply(): X }
In its companion object we tell the compiler how to create instances from instances of our non-covariant type class:
object GiveMeA {
implicit def fromGiveMeJustA[X](implicit giveMe: GiveMeJustA[X]): GiveMeA[X] =
new GiveMeA[X] { def apply() = giveMe() }
}
Now I'd expect implicitly[GiveMeA[Foo]]
to compile just fine, since there's only one way to get a GiveMeA[Foo]
given the pieces we have here. But it doesn't (at least not on either 2.10.4 or 2.11.2):
scala> implicitly[GiveMeA[Foo]]
<console>:16: this.GiveMeA.fromGiveMeJustA is not a valid implicit value for GiveMeA[Foo] because:
hasMatchingSymbol reported error: ambiguous implicit values:
both object GiveMeJustAFoo of type GiveMeJustAFoo.type
and object GiveMeJustABar of type GiveMeJustABar.type
match expected type GiveMeJustA[X]
implicitly[GiveMeA[Foo]]
^
<console>:16: error: could not find implicit value for parameter e: GiveMeA[Foo]
implicitly[GiveMeA[Foo]]
^
If we get rid of our irrelevant GiveMeJustA
instance, it works:
scala> implicit def GiveMeJustABar: List[Long] = ???
GiveMeJustABar: List[Long]
scala> implicitly[GiveMeA[Foo]]
res1: GiveMeA[Foo] = GiveMeA$$anon$1@2a4f2dcc
This is in spite of the fact that there's no way we can apply GiveMeA.fromGiveMeJustA
to this instance to get a GiveMeA[Foo]
(or any subtype of GiveMeA[Foo]
).
This looks like a bug to me, but it's possible that I'm missing something. Does this make any sense? Is there a reasonable workaround?
I do not understand why its working, but the following code resolves the implicit successfully in the current case (at least on scala v-2.10.1). However, this still not explains why your example is not working in the first place:
We change the implicit GiveMeA[X]
instance to search for implicit GiveMeJustA
instances where the type parameter is bounded upwards by X
, thus it searches for GiveMeJustA[_ <: X]
object GiveMeA {
implicit def fromGiveMeJustA[X](implicit giveMe: GiveMeJustA[_ <: X]) : GiveMeA[X] =
new GiveMeA[X] { def apply() = giveMe() }
}
We can then print out the expected output
val a = implicitly[GiveMeA[Foo]]
println(a()) // prints "Foo(foo)"
However, as soon as we introduce a new subclass
case class FooChild(s: String) extends Foo(s)
and the respective GiveMeJustA
typeclass instance
implicit object GiveMeJustAFooChild extends GiveMeJustA[FooChild] {
def apply() = FooChild("fooChild")
}
the compiler complains (as expected)
error: could not find implicit value for parameter e: GiveMeA[Foo]
val a = implicitly[GiveMeA[Foo]]
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With