I am very curious how Scala desugars the following for-comprehension:
for {
a <- Option(5)
b = a * 2
c <- if (b == 10) Option(100) else None
} yield b + c
My difficulty comes from having both b
and c
in the yield, because they seem to be bound at different steps
You can even ask the compiler. The following command:
scala -Xprint:parser -e "for {
a <- Option(5)
b = a * 2
c <- if (b == 10) Option(100) else None
} yield b + c"
yields this output
[[syntax trees at end of parser]] // scalacmd7617799112170074915.scala
package <empty> {
object Main extends scala.AnyRef {
def <init>() = {
super.<init>();
()
};
def main(args: Array[String]): scala.Unit = {
final class $anon extends scala.AnyRef {
def <init>() = {
super.<init>();
()
};
Option(5).map(((a) => {
val b = a.$times(2);
scala.Tuple2(a, b)
})).flatMap(((x$1) => x$1: @scala.unchecked match {
case scala.Tuple2((a @ _), (b @ _)) => if (b.$eq$eq(10))
Option(100)
else
None.map(((c) => b.$plus(c)))
}))
};
new $anon()
}
}
}
Taking only the piece you are interested in and improving the readability, you get this:
Option(5).map(a => {
val b = a * 2
(a, b)
}).flatMap(_ match {
case (_, b) =>
if (b == 10)
Option(100)
else
None.map(c => b + c)
})
As reported in a comment, literally translating from the compiler output seems to highlight a bug in how the desugared expression is rendered. The sum should be map
ped on the result of the if
expression, rather then on the None
in the else
branch:
Option(5).map(a => {
val b = a * 2
(a, b)
}).flatMap(_ match {
case (_, b) =>
(if (b == 10) Option(100) else None).map(c => b + c)
})
It's probably worth it to ask the compiler team if this is a bug.