Implementing a custom isInstanceOf[T] filter

I have a list of elements that I want to filter by type, and I want to avoid the verbose match case a: A => a case _ => and .collect { case a: A => a forms.

I want to define a .filterT method, like this

Seq(1, 3.333, 4)).filterT[Int]
// == Seq(1, 4)

Seq(1, 3.333, 4)).filterT[String]
// == Seq()

I tried to define it using ClassTag, which did work for distinguishing between String and Int, but it returns the same results for Int and Double. Maybe I’m doing it wrong. Perhaps isInstanceOf could be used internally.

Is this possible?

That’s because when you have Seq(1, 3.333, 4), the integers are implicitly converted to Double so the whole thing is Seq[Double].

scala> Seq(1, 2.3)
val res0: Seq[Double] = List(1.0, 2.3)

So your implementation is not the issue; type inference / conversion is.

Not sure if “conversion” is the correct term, searching the web a little, I think it’s called “numeric widening” and “weak conformance”. Looks like general weak conformance was dropped in Scala 3 but the Int to other numeric type adapting is the only one that remains.

If you do this:

Seq((1: Int), 3.333, (4: Int)).filterT[Double]

then it works.

1 Like

That is interesting, if you add a string to it, it also “works” that is:

println(Seq(1, 3.333, 4).filterT[Int])    => List()
println(Seq(1, 3.333, 4).filterT[Double]) => List(1.0, 3.333, 4.0)

whereas:

println(Seq(1, 3.333, "4").filterT[String]) => List(4)
println(Seq(1, 3.333, "4").filterT[Double]) => List(3.333)
println(Seq(1, 3.333, "4").filterT[Int])    => List(1)

so the conversion to Any takes place before the numeric widening.

So i suppose the trick is to force the type on beforehand:

println(Seq[Any](1, 3.333, 4).filterT[Int])    => List(1, 4)
println(Seq[Any](1, 3.333, 4).filterT[Double]) => List(3.333)
2 Likes

Cool! AnyVal also works.

1 Like