What does the @elidable annotation do in Scala, and when should I use it?

前端 未结 3 537
鱼传尺愫
鱼传尺愫 2021-02-05 05:09

I\'ve noticed in some of the scala library code, notably Predef, there is code like:

/** Tests an expression, throwing an `AssertionError` if false.         


        
3条回答
  •  生来不讨喜
    2021-02-05 05:33

    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).

    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).

    Long one

    My test code:

    import scala.annotation.elidable
    import scala.annotation.elidable._
    
    class Foobar {
        info()
        warning()
    
        @elidable(INFO) def info() {println("INFO")}
        @elidable(WARNING) def warning() {println("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."":()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
    

    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."":()V
       4:   aload_0
       5:   invokevirtual   #27; //Method warning:()V
       8:   return
    
    }
    

    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.

提交回复
热议问题