I'm trying to explore scala case class internals a bit. To do so I'm creating simple case classes and analyzing the bytecode that scala compiler creates using javap.
I'm quite surprised to find out that when I create a case class with only one String field:
case class MyCaseClass(value: String)
the bytecode of the companion object MyCaseClass$ contains two apply methods:
public MyCaseClass apply(java.lang.String);
Code:
0: new #23 // class MyCaseClass
3: dup
4: aload_1
5: invokespecial #26 // Method MyCaseClass."<init>":(Ljava/lang/String;)V
8: areturn
public java.lang.Object apply(java.lang.Object);
Code:
0: aload_0
1: aload_1
2: checkcast #53 // class java/lang/String
5: invokevirtual #55 // Method apply:(Ljava/lang/String;)LMyCaseClass;
8: areturn
(compiled using scalac 2.11.6)
The first one is the one I expected - taking String as an argument and creating a new instance of my case class passing this argument to the constructor. The second one takes an object, casts it to String and then calls the first one.
I cannot think of any uses of the second method. Why is it needed? Is this behavior documented anywhere?
The default companion object extends a function type, in this case Function1[String, MyCaseClass] (normally written as String => MyCaseClass in Scala).
The JVM signature of Function1#apply is Object apply(Object) so the overriding method must have the same signature.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With