Scala: filter vs withFilter

Scala provides two variations on “filter” which at first glance appear similar:

List("a", "b", "c").filter(_ == "b")
res3: List[String] = List(b)

Comparatively, “withFilter” takes the same syntax, but returns an object:

List("a", "b", "c").withFilter(_ == "b")
res4: scala.collection.generic.FilterMonadic[String,List[String]] = 
scala.collection.TraversableLike$WithFilter@32ae8f27

The difference between these two is that “withFilter” doesn’t do any work, until values are pulled from the collection. In this sense, it is exactly like a view, although it is a single function implementation vs. all the other features views would add.

Once you’ve applied “withFilter, you’re pretty committed – the resulting thing doesn’t let you switch back to filter, punishing you with an ugly error:

scala> List("a", "b", "c").withFilter(_ == "b").filter(x => true)
:12: error: value filter is not a member of 
scala.collection.generic.FilterMonadic[String,List[String]]

       List("a", "b", "c").withFilter(_ == "b").filter(x => true)

On the other hand, you can apply withFilter again:

List("a", "b", "c")
  .withFilter(_ == "b")
  .withFilter(x => true)

res7: scala.collection.generic.FilterMonadic[String,List[String]] = 
scala.collection.TraversableLike$WithFilter@144e36ae

To realize the resulting collection, you need to do whatever your final operation is (e.g. map), to get the results back:

List("a", "b", "c")
  .withFilter(_ == "b")
  .map(x => x)

res9: List[String] = List(b)

And there, you have the expected result.

Leave a Reply

Your email address will not be published. Required fields are marked *