В версиях Scala до 2.9.0 реализация конкретных функций в чертах была скомпилирована как обычные методы. Начиная с 2.9.x, они компилируются как мостовые методы. Я пытаюсь найти аргументы в пользу этого изменения, потому что это отрицательно сказывается на пользователях многих популярных фреймворков Java, таких как Spring и Jersey.
Рассмотрим следующий код Scala:
trait Speaks {
def speak() = {
println("woof")
}
}
class Dog extends Speaks {
def wag() = {
println("wag wag")
}
}
Когда класс Dog скомпилирован со скалярной версией 2.8.1 и декомпилируется с помощью javap, результат для функций "говорить" и "wag" выглядит следующим образом:
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
Когда Собака скомпилирована с версией 2.9.1 и снова декомпилирована, те же две функции выглядят так:
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
Проблематичной частью является добавление флага ACC_BRIDGE к функции talk(). Рамочные механизмы, такие как Джерси и Spring, намеренно не распознают методы моста во многих случаях как обходные пути для других проблем.
Так может ли кто-нибудь объяснить или указать на хорошее объяснение, почему это изменение было сделано в Scala 2.9.x?
В качестве продолжения можно ли отключить это поведение через аннотацию функции, флаг компилятора и т.д.