Question

Suppose I have this monadic class:

case class Foo[A](xs: List[A]) {
  def map[B](f: A => B) = Foo(xs map f)
  def flatMap[B](f: A => Foo[B]) = Foo(xs flatMap f.andThen(_.xs))
  def withFilter(p: A => Boolean) = {
    println("Filtering!")
    Foo(xs filter p)
  }
}

The following is from a 2.10.0 REPL session:

scala> for { (a, b) <- Foo(List(1 -> "x")) } yield a
res0: Foo[Int] = Foo(List(1))

And here's the same thing in 2.10.1:

scala> for { (a, b) <- Foo(List(1 -> "x")) } yield a
Filtering!
res0: Foo[Int] = Foo(List(1))

This is completely unexpected (to me), and leads to particularly confusing errors in cases where filtering requires additional constraints (such as Scalaz's \/ or EitherT).

I wasn't able to find any discussion of this change in the 2.10.1 release notes. Can someone point out where and why this new desugaring behavior was introduced?

Was it helpful?

Solution

The story is more complex than that, and it's in fact a 2.10.0 regression that was plugged there.

The "no-withFilter" behavior was introduced in c82ecab, and because of things like SI-6968, this was reverted partially #1893. Further adaptations followed (SI-6646, SI-7183)

The takeaway sentence you're looking for is :

The parser can't assume that a pattern (a, b) will match, as results of .isInstanceOf[Tuple2] can't be statically known until after the typer.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top