In Scala versions prior to 2.9.0, concrete function implementations in traits were compiled as normal methods. From 2.9.x onward, they are compiled as bridge methods. I'm trying to find the reasoning behind this change, because it negatively affects users of many popular Java frameworks like Spring and Jersey.
Consider the following Scala code:
trait Speaks {
def speak() = {
println("woof")
}
}
class Dog extends Speaks {
def wag() = {
println("wag wag")
}
}
When the Dog class is compiled with scalac version 2.8.1 and decompiled with javap, the result for the "speak" and "wag" functions look like this:
public void speak();
flags: ACC_PUBLIC
Code:
stack=1, locals=1, args_size=1
0: aload_0
1: invokestatic #11 // Method Speaks$class.speak:(LSpeaks;)V
4: return
LineNumberTable:
line 7: 0
public void wag();
flags: ACC_PUBLIC
Code:
stack=2, locals=1, args_size=1
0: getstatic #18 // Field scala/Predef$.MODULE$:Lscala/Predef$;
3: ldc #20 // String wag wag
5: invokevirtual #24 // Method scala/Predef$.println:(Ljava/lang/Object;)V
8: return
LineNumberTable:
line 9: 0
When Dog is compiled with scalac version 2.9.1 and again decompiled, the same two functions look like:
public void speak();
flags: ACC_PUBLIC, ACC_BRIDGE
Code:
stack=1, locals=1, args_size=1
0: aload_0
1: invokestatic #11 // Method Speaks$class.speak:(LSpeaks;)V
4: return
LineNumberTable:
line 7: 0
public void wag();
flags: ACC_PUBLIC
Code:
stack=2, locals=1, args_size=1
0: getstatic #18 // Field scala/Predef$.MODULE$:Lscala/Predef$;
3: ldc #20 // String wag wag
5: invokevirtual #24 // Method scala/Predef$.println:(Ljava/lang/Object;)V
8: return
LineNumberTable:
line 9: 0
The problematic part is the addition of the ACC_BRIDGE flag to the speak() function. Frameworks like Jersey and Spring intentionally do not recognize bridge methods in many cases as workarounds for other issues.
So can anyone explain or point to a good explanation of why this change was made in Scala 2.9.x?
As a followup, is there a way to disable this behavior through a function annotation, compiler flag, etc?
OK it sounds like there is no explanation as to why because it wasn't an intentional change. See this thread: http://groups.google.com/group/scala-language/browse_thread/thread/67f8884081d46912
And the solution is to use the newest snapshot, or, if the future has arrived as you read this, Scala 2.10
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