Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why are concrete function implementations in traits compiled to bridge methods in Scala 2.9.x but not in 2.8.x?

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?

like image 514
Janx Avatar asked Jan 05 '12 19:01

Janx


1 Answers

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

like image 152
Janx Avatar answered Nov 16 '22 17:11

Janx