Search code examples
scalapattern-matchingtype-safetyexistential-typescala-2.13

How to perform safe pattern matching on existential types in Scala 2.13?


Note: This is a contrived example.

Consider the following existential type.

sealed trait Showable

final case class Show[A](show: A => String, value: A) extends Showable

I can define a show method as follows:

def show(showable: Showable): String = showable match {
  case Show(show, value) => show(value)
}

But the pattern match infers the type Any => String and Any for show and value respectively. Hence, I can also define a show method as follows:

def show(showable: Showable): String = showable match {
  case Show(show, value) => show(42)
}

This is unsafe. How do I ensure that within the case expression show can only be applied to value?


Solution

  • If you match a typed pattern then

    def show(showable: Showable): String = showable match {
      case s: Show[a] => s.show(s.value)
    }
    

    or

    def show(showable: Showable): String = showable match {
      case s: Show[_] => s.show(s.value)
    }
    

    compiles but

    def show(showable: Showable): String = showable match {
      case s: Show[a] => s.show(42)
    }
    //type mismatch;
    // found   : Int(42)
    // required: a
    

    or

    def show(showable: Showable): String = showable match {
      case s: Show[_] => s.show(42)
    }
    //type mismatch;
    // found   : Int(42)
    // required: _
    

    doesn't.