为什么特征中的具体函数实现在 Scala 2.9.x 中被编译为桥接方法,但在 2.8.x 中却没有?

发布于 2024-12-25 09:33:35 字数 2038 浏览 0 评论 0原文

在 2.9.0 之前的 Scala 版本中,traits 中的具体函数实现被编译为普通方法。从 2.9.x 开始,它们被编译为桥接方法。我正在尝试找出此更改背后的原因,因为它对 Spring 和 Jersey 等许多流行 Java 框架的用户产生了负面影响。

考虑以下 Scala 代码:

trait Speaks {
  def speak() = {
    println("woof")
  }
}

class Dog extends Speaks {
  def wag() = {
    println("wag wag")
  }
}

当使用 scalac 版本 2.8.1 编译 Dog 类并使用 javap 反编译时,“speak”和“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

当使用 scalac 版本 2.9.1 编译 Dog 时,再次反编译,相同的两个函数如下所示:

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

有问题的部分是在 talk() 函数中添加了 ACC_BRIDGE 标志。像 Jersey 和 Spring 这样的框架在许多情况下故意不识别桥接方法作为其他问题的解决方法。

那么有人可以解释或指出为什么在 Scala 2.9.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?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

韵柒 2025-01-01 09:33:35

好吧,听起来好像没有解释为什么,因为这不是故意的改变。请参阅此线程:
http://groups.google.com/group/scala-language/browse_thread/thread/67f8884081d46912< /a>

解决方案是使用最新的快照,或者,如果您在阅读本文时未来已经到来,则使用 Scala 2.10

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

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文