Consider the following piece of code:
trait Foo {
type T
def value: T
}
object Foo {
def apply[A](v: A): Foo = new Foo {
override type T = A
override def value = v
}
}
trait Decode[A] {
def apply(x: A): String
}
object Decode {
def apply[A](f: A => String): Decode[A] = new Decode[A] {
override def apply(x: A) = f(x)
}
implicit val decodeStr: Decode[String] = Decode(identity)
}
class Sandbox {
def decodeFoo(foo: Foo)(implicit decoder: Decode[foo.T]): String =
decoder(foo.value)
val foo = Foo("hello")
println(decodeFoo(foo))
}
The above code should work fine and print hello
but instead it fails to compile:
could not find implicit value for parameter decoder: Decode[Sandbox.this.foo.T]
[error] println(decodeFoo(foo))
Even when I explicitly pass in the implicit param:
println(decodeFoo(foo = foo)(decoder = Decode.decodeStr))
I still get this error now:
type mismatch;
[error] found : Decode[String]
[error] required: Decode[Sandbox.this.foo.T]
[error] println(decodeFoo(foo = foo)(decoder = Decode.decodeStr))
[error] ^
Ofcourse, I can make Foo
a Foo[T]
and define decoders for it but that's not the point of this question - I want to understand why the above code fails to compile.
The problem exists here:
object Foo {
def apply[A](v: A): Foo = new Foo {
override type T = A
override def value = v
}
}
There, you've established that you will return a Foo
but not, specifically, which Foo
. Hence, that function only knows that it can return a Foo
for any type T
. You need an Aux
pattern to recapture the type which is lost when establishing your new Foo
(yes, yes...)
object Foo {
type Aux[A] = Foo{ type T = A }
def apply[A](v: A): Aux[A] = new Foo {
type T = A
def value = v
}
}
which then says that for a given A
produce the Foo
which has it's T
dependent type set to A
.