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?
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
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