Reputation: 542
I suppose that for-comprehension which I see as "for every 'a' create 'x' and then for every 'b' do some stuff with all of vars"
for {
a <- Seq(1, 2, 3)
x = "test" + a
b <- Seq(4, 5, 6)
} {
...
}
should be expanded to
Seq(1, 2, 3).foreach { a =>
val x = "test" + a
Seq(4, 5, 6).foreach { b =>
...
}
}
but surprisingly check with -Xprint:parser
shows that it expands to
Seq(1, 2, 3).map { a =>
val x = "test" + a
(a, x)
}.foreach { case (a, x) =>
Seq(4, 5, 6).foreach { b =>
...
}
}
I think it breaks the natural understanding of what's going on in whole for-comprehension, coz now it is firstly define three different 'x' and then executes other stuff. It may be critical if definition of 'x' can produce side-effects so what's the purpose of desugaring to map
?
Upvotes: 0
Views: 176
Reputation: 14224
This behaviour is surprising, but it's documented in Scala specification: https://scala-lang.org/files/archive/spec/2.13/06-expressions.html#for-comprehensions-and-for-loops
According to the last rule there:
A generator 𝑝 <- 𝑒 followed by a value definition 𝑝′ = 𝑒′ is translated to the following generator of pairs of values, where 𝑥 and 𝑥′ are fresh names:
(𝑝, 𝑝′) <- for (𝑥@𝑝 <- 𝑒) yield { val 𝑥′@𝑝′ = 𝑒′; (𝑥, 𝑥′) }
So when there is a value definition, Scala always inserts a new for-comprehension with a yield
, which then becomes map
.
And if you replace the value definition line x = "test" + a
with a generator x <- Seq("test" + a)
, the result becomes as expected:
Seq(1, 2, 3)
.foreach(((a) => Seq("test".$plus(a))
.foreach(((x) => Seq(4, 5, 6)
.foreach(((b) => ...))))))
Upvotes: 5