Scala code:
val list = List(1, 2, 3)
for {
item <- list
_ = println("1111111111")
} yield {
println("XXXXXXXXX")
item + 1
}
I expected it to print:
1111111111
XXXXXXXXX
1111111111
XXXXXXXXX
1111111111
XXXXXXXXX
But actually it prints:
1111111111
1111111111
1111111111
XXXXXXXXX
XXXXXXXXX
XXXXXXXXX
I can't understand this because I thought the code will be expanded like:
val list = List(1, 2, 3)
list.map { item =>
val _ = println("1111111111")
println("XXXXXXXXX")
item + 1
}
Which should print XXXXXXXX
just before 11111111
in each loop.
The Scala specification, in section 6.19 "For Comprehensions and For Loops", clearly describes the behavior:
A generator p <- e followed by a value definition p' = e' is translated to the following generator of pairs of values, where x and x' are fresh names:
(p, p') <- for ( x@p <- e ) yield { val x'@p' = e' ; (x, x') }
As an example, the code
for {x <- xs; y = 1} yield {x+y}
is desugared to
xs.map{x => val y = 1; (x,y)}.map{ case (x,y) => x+y}
In your case it would be
xs.map{x => val x$1 = println("1"); (x,x$1)}.map{ case (x,_) => x+1}
where the second value of the tuple is thrown away.
What you're seeing is the following desugar of the map
function:
def map[B](f: A => B)(implicit cbf: CanBuildFrom[B, List[A], List[B]]): List[B] ={
val b = new ListBuffer[B]
var xs = this
while(!xs.isEmpty){
b += f(xs.head) //calls "f" here which activates the println
xs = xs.tail
}
b result ()
}
which actually first iteratively creates each element of the new list by successively calling f
and then it returns that created list. Do note that f
in this case is not what is in the yield. That is another function which is called in addition to what is in the for comprehension body.
Hence, it's going to print out "1111111"
before it ever returns the results you'd like to see followed by what is in the yield
block.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With