Reputation: 45775
I was following the technique presented in the accepted answer to this question How to define "type disjunction" (union types)? in order to support type checking for a multiple-type parameter to a method.
The implicit "evidence"
@implicitNotFound(msg="Only String, Array[Byte] and InputStream are supported")
sealed class Input[T]
object Input{
implicit object ByteArrayWitness extends Input[Array[Byte]]
implicit object StringWitness extends Input[String]
implicit object InputStreamWitness extends Input[InputStream]
}
The API method
def foo[T: Input](param: T) =
param match {
case x: String => //...
case x: Array[Byte] => //...
case x: InputStream => //...
case _ => throw new UnsupportedOperationException(s"not implemented for type ${param.getClass}")
}
The Problem
this compiles
foo("test")
foo(Array[Byte](123.toByte))
but this does not (because it's not a concrete InputStream
)
foo(new ByteArrayInputStream("abc".getBytes("UTF-8")))
I have to cast it to the exact super type to make it work (this compiles)
foo(new ByteArrayInputStream("abc".getBytes("UTF-8")).asInstanceOf[InputStream])
Is there a way to change
implicit object InputStreamWitness extends Input[InputStream]
So that it is an evidence for everything that extends InputStream
? I have a feeling there is some upper bound <:
notation to plug in somewhere, I just really don't know where...
Or is this where the "crazy lambda calculus stuff" from the highest voted answer to the aforementioned question comes to the rescue?
Upvotes: 5
Views: 477
Reputation: 21567
Make Input
contra variant in type T
like: Input[-T]
, it means that if A is super type of B, then Input[B] is super type of Input[A] (reverse "inheritance"). In your case it simply means that Input[InputStream] knows how to handle all subclasses input type InputStream
(like ByteArrayInputStream
)
I really like the explanation on contravariance by Rex Kerr in this question. But there are many others
Upvotes: 8