In this code:
class Foo[T] {
def bar(i: T) = i
}
object Main {
def main(args: Array[String]) {
val f = new Foo[Int]
f.bar(5)
}
}
The invocation of bar
should first box the integer. Compiling with Scala 2.8.1 and using:
javap -c -l -private -verbose -classpath <dir> Main$
to see the bytecode produced for the main
method of the Main
class yields:
public void main(java.lang.String[]);
...
9: iconst_5
10: invokestatic #24; //Method scala/runtime/BoxesRunTime.boxToInteger:(I)Ljava/lang/Integer;
13: invokevirtual #28; //Method Foo.bar:(Ljava/lang/Object;)Ljava/lang/Object;
16: pop
17: return
...
You can see the call to BoxesRunTime
before the call to bar
.
BoxesRunTime
is an object which contains boxing methods for primitive types, so there should be exactly one instance in total. The trick here is that this particular file in the library was written in Java, and the conversions are static methods. For this reason there aren't any instances of it at runtime, although using it in Scala code feels as if it were an object.
You should probably look for boxed primitives (e.g. java.lang.Integer) with JProfile, though I am uncertain how the JVM works and whether it may actually rewrite the code at runtime and optimize it to avoid boxing. To my knowledge, it shouldn't apply specialization (but I believe CLR does). A few microbenchmarks with and without the boxing situation are another way to figure out what happens at runtime.
EDIT:
The above is assuming that a type parameter wasn't annotated with the @specialized
annotation. In this case, the boxing/unboxing can be avoided. Certain classes in the standard library are specialized. See this sid.
Test$$anonfun$#
, since functions are specialized. However, these function anonymous classes are used within themap
andfilter
methods which are not specialized and call their default genericapply
, which expects an object - the boxing should occur there. If you decompile the code ofTraversableLike
, and search formap
orfilter
, they should have invocations toBoxesRunTime
. – Numismatics