且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

@elidable 注释在 Scala 中有什么作用,我应该什么时候使用它?

更新时间:2023-02-16 22:28:27

简短回答

方法和对它的所有调用都会消失.这可能是用于日志记录的好主意,因为每个日志记录框架都会在调用日志记录但禁用给定级别(计算有效级别并准备参数)时引入一些开销.

Short answer

Both method and all calls to it simply disappear. This might be a good idea to use for logging since every logging framework introduces some overhead when logging is called but a given level is disabled (computing the effective level and preparing arguments).

请注意,现代日志框架试图尽可能地减少这种占用空间(例如 Logback 优化了 is*Enabled() 调用和 SLF4S 按名称传递消息以避免不必要的字符串连接).

Note that modern logging frameworks try to reduce this footprint as much as possible (e.g. Logback optimizes is*Enabled() calls and SLF4S passes message by name to avoid unnecessary string concatenations).

我的测试代码:

import scala.annotation.elidable
import scala.annotation.elidable._

class Foobar {
    info()
    warning()

    @elidable(INFO) def info() {println("INFO")}
    @elidable(WARNING) def warning() {println("WARNING")}
}

证明 -Xelide-below 800 两个语句都打印出来,而 900 只出现 "WARNING".那么引擎盖下会发生什么?

Proves that with -Xelide-below 800 both statements are printed while with 900 only "WARNING" appears. So what happens under the hood?

$ scalac -Xelide-below 800 Foobar.scala && javap -c Foobar

public class Foobar extends java.lang.Object implements scala.ScalaObject{
public void info();
//...

public void warning();
//...

public Foobar();
  Code:
   0:   aload_0
   1:   invokespecial   #26; //Method java/lang/Object."<init>":()V
   4:   aload_0
   5:   invokevirtual   #30; //Method info:()V
   8:   aload_0
   9:   invokevirtual   #32; //Method warning:()V
   12:  return
}

如您所见,这可以正常编译.但是,当使用此指令时:

As you can see this compiles normally. However when this instruction is used:

$ scalac -Xelide-below 900 Foobar.scala && javap -c Foobar

调用 info() 并且方法本身从字节码中消失:

calls to info() and the method itself disappears from the bytecode:

public class Foobar extends java.lang.Object implements scala.ScalaObject{
public void warning();
//...

public Foobar();
  Code:
   0:   aload_0
   1:   invokespecial   #23; //Method java/lang/Object."<init>":()V
   4:   aload_0
   5:   invokevirtual   #27; //Method warning:()V
   8:   return

}

我希望 NoSuchMethodError 在运行时被抛出,当从针对 Foobar 版本编译的客户端代码中调用删除的方法时,elide-below临界点 .它也闻起来像旧的 C 预处理器,因此在使用 @elidable 之前我会三思而后行.

I would expect that NoSuchMethodError is thrown at runtime when removed method is called from client code compiled against Foobar version with lower elide-below threshold . Also it smells like good old C preprocessor, and as such I would think twice before employing @elidable.