Below is the source for the reduceLeft method of Scala’s TraversableOnce trait. What is happening with the line that reads var acc: B = 0.asInstanceOf[B]?
To me, it seems that if I call this on a list of Strings, such as List("a", "b", "c"), this would result in something like 0.asInstanceOf[String]. However, 0.asInstanceOf[String] throws a ClassCastException at run time if I try it directly.
What is happening with that line, and why is it different than calling 0.asInstanceOf[String] directly when called on a list of Strings?
def reduceLeft[B >: A](op: (B, A) => B): B = {
if (isEmpty)
throw new UnsupportedOperationException("empty.reduceLeft")
var first = true
var acc: B = 0.asInstanceOf[B]
for (x <- self) {
if (first) {
acc = x
first = false
}
else acc = op(acc, x)
}
acc
}
Bonus question: why is acc even initialized to that value? It looks like the code in the first iteration of the for loop will just overwrite that value with the first element in the TraversableOnce object.
Well, the reason this is not failing with a
ClassCastExceptionat runtime is either because:Object(orAnyRef), hence the cast is really0.asInstanceOf[Object]You could test the first possibility by checking the bytecode but it seems a pointless piece of code. If it is not elided, then this has the unnecessary overhead of boxing an
Inton every call to the method (although not an object creation – see below)!Figuring out what the compiler produces: 1
So now:
Make of that what you will!
Figuring out what the compiler produces: 2
One other possibility is to put this in a source file and compile it, printing out the intermediate code phase:
then you get…
It looks distinctly like the unnecessary boxing is in there! One point is that this won’t involve an object creation, merely a lookup, because the boxed values of -127 to 127 are cached.
You can check the erased line by changing the compiler phase in the above print command to “erasure”. Hey presto: