Eran Medan
Eran Medan

Reputation: 45775

Union type with upper bound

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

Answers (1)

4lex1v
4lex1v

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

Related Questions