I was playing around with the following piece of code:
class A
class B
class C
trait Codecs[L] {
case class Codec[R](val code: L => R, val decode: R => L)
object Codec
def code[R](foo: L)(implicit codec: Codec[R]): R = codec.code(foo)
def decode[R](bar: R)(implicit codec: Codec[R]): L = codec.decode(bar)
}
object Codecs {
implicit object ACodecs extends Codecs[A] {
object Codec {
implicit val ab: Codec[B] = new Codec(_ => new B, _ => new A)
implicit val ac: Codec[C] = new Codec(_ => new C, _ => new A)
}
}
}
object test extends App {
val codecs = implicitly[Codecs[A]]
codecs.code[B](new A)
}
It won't compile, as the compiler is unable to find an implicit value of type Codecs.Codec[B]
.
As I understand, the two values ab
and ac
are of type Acodecs.Codec[_]
(or something like that), which isn't exactly what the compiler is looking for. I am also aware that moving the case class Codec[_]
and its companion outside of the trait solves the problem (after making it take 2 type params). If an implicit value is required, the compiler should include the companion object of the required type in the implicit scope. My questions are:
- How do I point the compiler at the companion of a path-dependent subtype, more specifically:
- Is it possible to alter the signature of the two methods of the
trait
(ideally alter the type signature of the implicit param) to make this compile? How would one refer to the typeAcodecs.Codec[_]
from inside the traitCodecs[_]
? Like, how do you do this typeclass thing on a nested type?
Is there like a pattern or something dealing with this sort of problem?