1

I'm trying to write some generic testing software for various types using a parameterized base class. I get match errors though on code which I don't believe should be possible.

abstract class AbstractTypeTest[TestType: ClassTag, DriverType <: AnyRef : ClassTag]( 
  def checkNormalRowConsistency(
    expectedKeys: Seq[TestType],
    results: Seq[(TestType, TestType, TestType)]) {

    val foundKeys = results.filter {
      case (pkey: TestType, ckey: TestType, data: TestType) => expectedKeys.contains(pkey)
      case x => throw new RuntimeException(s"${x.getClass}")
    }
    foundKeys should contain theSameElementsAs expectedKeys.map(x => (x, x, x))
  }
}

An extending class specifies the parameter of TypeTest but this code block throws Runtime Exceptions (because we don't match what I believe should be the only allowed type here)

The output of the above code with some extended types works but with others it does not, in this case I'm extending this class with TestType --> Int

[info]   java.lang.RuntimeException: class scala.Tuple3

I can remove the type on the filter and the ScalaTest check works perfectly but I'd like to understand why the MatchError occurs.

RussS
  • 16,476
  • 1
  • 34
  • 62
  • Most likely the runtime type of what you pass into `results` does not match the pattern (that could happen for example when you use `asInstanceOf`. Can you give an example code that calls to `checkNormalRowConsistency` that make it throw this exception? – thesamet Oct 29 '15 at 02:07
  • That could be it, it uses some rather complicated internal functions to generate the input. val result = sc.cassandraTable[(TestType, TestType, TestType)](keyspaceName, table).collect Which invokes some type converters on the Spark side and then should return via serialization List[(TestType,TestType,TestType)] – RussS Oct 29 '15 at 03:48
  • This does work in regular Scala and it does not look like type erasure which I suspected at first. You can look at the bytecode to understand what is being passed into it. – yǝsʞǝla Oct 29 '15 at 06:07

1 Answers1

1

If you're on Scala 2.10, then

ClassTag based pattern matching fails for primitives

scala> import reflect._
import reflect._

scala> def f[A: ClassTag](as: Seq[(A,A,A)]) = as filter {
     | case (x: A, y: A, z: A) => true ; case _ => false }
f: [A](as: Seq[(A, A, A)])(implicit evidence$1: scala.reflect.ClassTag[A])Seq[(A, A, A)]

scala> val vs = List((1,2,3),(4,5,6))
vs: List[(Int, Int, Int)] = List((1,2,3), (4,5,6))

scala> f(vs)
res0: Seq[(Int, Int, Int)] = List()

versus 2.11

scala> f[Int](vs)
res4: Seq[(Int, Int, Int)] = List((1,2,3), (4,5,6))
Community
  • 1
  • 1
som-snytt
  • 39,429
  • 2
  • 47
  • 129