Pattern Matching with Type Parameter variable

I have recently found that I can use a variable to hold a value of a type parameter and use it later in the pattern matching context. For instance:

Defining a case class as TupleData[A,B](a: A, b: B) and then using that in a match statement:

  case t: TupleData[b,c] =>
    val bF: Json => Either[String,b] = recursiveCall(t.a)
    val cF: Json => Either[String,c] = recursiveCall(t.b)

Note how I was able to specify type parameter variables b and c and then use that variable as I would use a type.

I ran across this by mistake and have been looking for documentation on it. I am giving a presentation using this pattern and it would be nice to use the standard nomenclature. If anyone knows of the documentation on this feature (it is not in the pattern match tutorial), or could help me with the nomenclature, that would be appreciated.

In the 2.12 spec, this is called a Typed Pattern (8.1.2) and explained in detail in (8.2).

A parameterized type pattern T[a1,…,an], where the ai are type variable patterns or wildcards _. This type pattern matches all values which match T for some arbitrary instantiation of the type variables and wildcards. The bounds or alias type of these type variable are determined as described here.

which links to (8.3 Type Parameter Inference in Patterns) for details.

I’ll admit, i wasn’t fully aware of the complexity of this functionality. I’d have thought type erasure would wreak havoc, but apparently it’s not as simple as i’d have thought.

1 Like

You can do the same trick with regular tuples:

  def test1(param: (_, _)): Unit = {
    param match {
      case t: Tuple2[b, c] =>
        val bF: String => Either[String, b] = ???
        val cF: String => Either[String, c] = ???
    }
  }

although you can do it differently:

  def test2(param: (_, _)): Unit = {
    param match {
      case (b: AnyRef, c: AnyRef) => // AnyRefs to silence compiler errors
        val bF: String => Either[String, b.type] = ???
        val cF: String => Either[String, c.type] = ???
    }
  }

I suspect the types b and c in test1 and b.type and c.type in test2 are called path dependent types, but I’m not sure.