Filter a list by type by using manifests in Scala
Due to the type erasure in Scala I got problems when I tried to create a function filterType<T>(list: List[Any]): List[T] that simply filters out all elements in a list of type T. This is the naive implementation that I first tried out:
object TypeFiltering {
def typeFilter[T](list: List[Any]): List[T] = list.filter {
_ match {
case _: T => true
case _ => false
}}.asInstanceOf[List[T]]
def main(args: Array[String]) {
val list = List(1,2,3,"a","b","c")
println("strings: " + typeFilter[String](list))
println("bools: " + typeFilter[Boolean](list))
}
}
/*
Output:
strings: List(1, 2, 3, a, b, c)
bools: List(1, 2, 3, a, b, c)
*/
What happened here is essentially that the type erasure mechanism that exists both in Java and Scala (but not in C#) removes the type T from the line
case _: T => truewhich just leaves
_ => truewhich will always match, obviously.
I consulted the very helpful Scala community at irc.freenode.net/#scala and got the suggestion that I should use the undocumented and still experimental Scala manifests. Jorge Ortiz has written a very instructive blog post about what manifests are and how you use them. I ended up with this typeFilter function:
def typeFilter[T](l:List[Any])(implicit m:scala.reflect.Manifest[T]) =
l.filter{x:Any => m.erasure.isInstance(x)}.asInstanceOf[List[T]]
/*
Output:
strings: List(a, b, c)
bools: List()
*/