David Portabella David Portabella - 4 months ago 8
Scala Question

How does TraversableLike.exists invoke my custom collections foreach

This code returns true as expected:

class MyList extends Traversable[Int] {
def foreach[U](f: Int => U) = {
f(1)
f(2)
f(3)
}
}
object Test extends App {
println(new MyList().exists(_ == 2))
}


MyList
only needs to define
foreach
in order to implement a
Traversable
. So, somewhere the
exists
function calls
MyList.foreach
. Setting a breakpoint at
f(1)
, I see that
foreach
is called by
TraversableLike
line 352
for (x <- this)
. So, is
x <- this
calling foreach? How? I don't see the call to
foreach
anywhere.

349: def exists(p: A => Boolean): Boolean = {
350: var result = false
351: breakable {
352: for (x <- this)
353: if (p(x)) { result = true; break }
354: }
355: result
366: }

Answer

The Scala specification regarding For Comprehension and For Loops talks about this exactly:

The precise meaning of generators and guards is defined by translation to invocations of four methods: map, withFilter, flatMap, and foreach. These methods can be implemented in different ways for different carrier types.

So the translation is effectively:

def exists(p: A => Boolean): Boolean = {
  var result = false
  breakable {
    this.foreach(x => if (p(x)) { result = true; break })
  }
  result
}

And that is why you're see your foreach being invoked.

For different for comprehensions you may see different translations, which are all specified in the specification.