Simple Scala puzzle
Who can guess what this tiny* Scala program does?
object O extends App { val x = 123456789L val y = 0F val z = x − (if (true) x else y) println(z) }
(Apparently this mysterious snippet had been going around a while ago, but I only recently encountered a variation.)
Answer: Prints “−3.0”.
Why?
Short answer: The if/else causes x
to get promoted to Float, which rounds it up to 123456792.
Long answer after the fold.
The expression (if (true) x else y)
must have a type, and since Scala is statically typed, that type depends on the types of x
and y
only, without regard to the if
’s condition — (if (false) x else y)
would have the exact same type. That type is Float.
But why is it Float and not Long or Double? Why is the if
expression even interpreted to have a meaningful type when its x
and y
components don’t have matching types? That’s due to Scala’s implicit conversions. scala.Predef
contains a “long2float
” method that implicitly converts x
to y
’s type, and there’s no “float2long
” to compete with it, so x
is converted to Float by a call to scala.Predef.long2float
, and its output value is used as the value of the if
expression.
Fine, but why does that result in 123456789 turning into 123456792? That’s because single-precision floating point provides 24 bits (8 octal digits) for the significand†, but 123456789 takes 27 bits to represent — it’s 111,0101,1011,1100,1101,0001,0101bin and 726,746,425oct. Rounding the 9-digit octal number to the 8 digits that fit in a Float‡ gives 726,746,430oct, which is 123456792dec. And that explains why it’s “−3”: 5oct rounds up by 3 to 10oct, and by rounding up instead of down it makes the difference from x
negative.
* At just 115 characters, this could be twitcode #5 if demonstrating counterintuitive behavior qualifies as useful enough to count.
† including the implicit leading bit
‡ The rounding in octal matches the rounding in binary because the high bit of the leading octal digit is set, so the leading n octal digits are exactly the leading 3n binary digits.