In the following example I would like to be capable to use an implicit type class - Process - wit a trait as input. But the compilator does not recognize any implicit in that case. I was expecting as Input is a sealed trait and I made the implicits implementation for both InputA and InputB that during the runtime it select by itself accordingly to the type provided.
sealed trait Input
final case class InputA(i: Int) extends Input
final case class InputB(s: String) extends Input
trait Process[U] {
def give(u :U): U
}
object Process {
implicit val processInputA: Process[InputA] = (u: InputA) => u.copy(i = u.i+10)
implicit val processInputB: Process[InputB] = (u: InputB) => u.copy(s = u.s+"add")
}
object UseProcess {
def run[U](u: U)(implicit process: Process[U]): U = process.give(u)
}
val g: Input = InputB("1")
val res3: Input = UseProcess.run(g). ==>> No implicits found for parameter process: Process[Input]
Is there a way to have it working or type class work only with implementation on concrete type.
Thanks in advance for your answer
It is not about trait vs class.
The method you are calling looks like this
In order to call, the compiler needs to find an implicit instance of type
Process[Input]somewhere in scope, but there aren't any.Note, that
Process[InputB]is not a subclass ofProcess[Input]becauseProcessis invariant in its parameter. You could try to make it covariant liketrait Process[+U]... but that won't work in this case, because function parameters are contravariant (you can't havegive(u: U)ifUis covariant).If you could make your trait covariant though, it still wouldn't work, because now both
processInputAandprocessInputBwould fit, so the resolution would be ambiguous.Basically, upcasting to
Inputatg: Inputis a bad idea. If you are writing a function where you want to use the trait for abstraction, you should parameterize it:^^ this should work.