Reputation: 188
I do not understand why in Scala polymorphic method do not work as I expected.
lets have method:
def sth[T](list: Iterable[Any]): List[T] = {
list.collect({case s:T => s}).toList
}
not I would like to get only Boolean from my list. so I would write:
val out = sth[Boolean](List(true, false, 2.0, 2, 4, 12.3))
What I expect is List(true, false)
and IntelIJ shows me that out
is instance of: List[Boolean]
BUT what this method returns me is my input list: List(true, false, 2.0, 2, 4, 12.3)
I also did try with list.filter(s => s.isInstanceOf[T])
but had same result.
I'm a little bit confused. Can u explain me what have I done wrong?
Upvotes: 1
Views: 128
Reputation: 48430
Due to type erasure the check
case s:T => ...
becomes something like
if (s.isInstanceOf[Object]) ...
as indicated by the compiler warning message
warning: abstract type pattern T is unchecked since it is eliminated by erasure
list.collect({case s:T => s}).toList
Try providing ClassTag like so
import scala.reflect.ClassTag
def collect[T: ClassTag](list: Iterable[Any]): List[T] = {
list.collect({ case s: T => s }).toList
}
collect[Boolean](List(true, false, 2.0, 2, 4, 12.3))
collect[Double](List(true, false, 2.0, 2, 4, 12.3))
which outputs
res0: List[Boolean] = List(true, false)
res1: List[Double] = List(2.0, 12.3)
which works due to some compiler magic explained here.
Here is our own type class solution
trait Collectable[T] {
def collect(list: Iterable[Any]): List[T]
}
object Collectable {
def collect[T](list: Iterable[Any])(implicit ev: Collectable[T]): List[T] =
ev.collect(list)
implicit val booleanCollect: Collectable[Boolean] =
(list: Iterable[Any]) => list.collect({ case s: Boolean => s }).toList
implicit val doubleCollect: Collectable[Double] =
(list: Iterable[Any]) => list.collect({ case s: Double => s }).toList
}
import Collectable._
collect[Boolean](List(true, false, 2.0, 2, 4, 12.3))
collect[Double](List(true, false, 2.0, 2, 4, 12.3))
which outputs
res0: List[Boolean] = List(true, false)
res1: List[Double] = List(2.0, 12.3)
Upvotes: 8