Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Scala: isInstanceOf followed by asInstanceOf

Tags:

scala

In my team, I often see teammates writing

list.filter(_.isInstanceOf[T]).map(_.asInstanceOf[T])

but this seems a bit redundant to me.

If we know that everything in the filtered list is an instance of T then why should we have to explicitly cast it as such?


I know of one alternative, which is to use match.

eg:

list.match {
  case thing: T => Some(thing)
  case _ => None
}

but this has the drawback that we must then explicitly state the generic case.


So, given all the above, I have 2 questions:

1) Is there another (better?) way to do the same thing?

2) If not, which of the two options above should be preferred?

like image 760
Chris Mukherjee Avatar asked Dec 14 '22 01:12

Chris Mukherjee


1 Answers

You can use collect:

list collect {
  case el: T => el
}

Real types just work (barring type erasure, of course):

scala> List(10, "foo", true) collect { case el: Int => el } 
res5: List[Int] = List(10)

But, as @YuvalItzchakov has mentioned, if you want to match for an abstract type T, you must have an implicit ClassTag[T] in scope.

So a function implementing this may look as follows:

import scala.reflect.ClassTag

def filter[T: ClassTag](list: List[Any]): List[T] = list collect {
  case el: T => el
} 

And using it:

scala> filter[Int](List(1, "foo", true))
res6: List[Int] = List(1)

scala> filter[String](List(1, "foo", true))
res7: List[String] = List(foo)

collect takes a PartialFunction, so you shouldn't provide the generic case.

But if needed, you can convert a function A => Option[B] to a PartialFunction[A, B] with Function.unlift. Here is an example of that, also using shapeless.Typeable to work around type erasure:

import shapeless.Typeable
import shapeless.syntax.typeable._

def filter[T: Typeable](list: List[Any]): List[T] = 
  list collect Function.unlift(_.cast[T])

Using:

scala> filter[Option[Int]](List(Some(10), Some("foo"), true))
res9: List[Option[Int]] = List(Some(10))
like image 83
Kolmar Avatar answered Dec 21 '22 12:12

Kolmar