Search code examples
scalacovariance

How does Scala handle Any to AnyVal covariance in method return types?


An example is worth a thousand words:

class A { def foo: Any = new Object }

class B extends A {
  override def foo: AnyVal = 42
}

In Java, the signature @Override public int foo() wouldn't even be allowed, and the overridden method foo in B could only return the wrapper integer type (@Override java.lang.Integer foo()).

Is Scala able to avoid the boxing/unboxing of AnyVal values in the overridden def foo: AnyVal method above?


Solution

  • No, it does not. Scala has to adhere to emitting the correct bytecode:

    λ scalac -Xprint:jvm Bar.scala
    [[syntax trees at end of                       jvm]] // Bar.scala
    package yuval.tests {
      class A extends Object {
        def foo(): Object = new Object();
        def <init>(): yuval.tests.A = {
          A.super.<init>();
          ()
        }
      };
      class B extends yuval.tests.A {
        override def foo(): Object = scala.Int.box(42);
        def <init>(): yuval.tests.B = {
          B.super.<init>();
          ()
        }
      }
    }
    

    You can see that although AnyVal was permitted in Scala, the actual method signature for the emitted foo is Object and not AnyVal, and Int is boxed.