3
votes

Assume this simple trait. A trait which exposes a val x. Since the initialization costs of x are very high I choose val x =... over def x =...

trait ScalaTrait {

  self =>

  val x: Int = SomeVeryExpensiveOperation.do()

}

Now how about a Java class implementing this trait. I'm of course obliged to implement val x using a public method in my Java class. But here is the catch: because the public method and my trait's val x share the same name I can't just delegate to the trait implementation:

class JavaClass imlements ScalaTrait {
    @Override
    public x() {
        /* I can't hand over this call to x() of the trait,
           since this would be a recursive call inside the Java class itself*/
        return x(); <-- so, this no can do!
    }

}

My question is what exactly should go inside method x()?

As an alternative I could provide a public def accessor to that private val x field. Like so:

trait ScalaTrait {

  self =>

  private val _x: Int = SomeVeryExpensiveOperation.do()
  def x = _x

}

But still, I'm now forced to implement that private val _x in my Java class, too, regardless of the private access modifier. How can I make this work and why must my Java class implement the private val field in the first place?

1

1 Answers

3
votes

You don't really want to do this. You're going to have to dive into the guts of how Scala implements mixins and reimplement it by hand in Java.

Here is a simple example, all in Scala:

trait X {
  val x = 5
}

class Y extends X

We can use scalac -Xprint:mixin to get an intermediate stage in the Scala compilation process that shows what Scala does to implement Y:

[[syntax trees at end of                     mixin]] // test20.scala
package <empty> {
  abstract trait X extends Object {
    <accessor> def X$_setter_$x_=(x$1: Int): Unit;
    <stable> <accessor> def x(): Int
  };
  class Y extends Object with X {
    <stable> <accessor> def x(): Int = Y.this.x;
    private[this] val x: Int = _;
    <accessor> def X$_setter_$x_=(x$1: Int): Unit = Y.this.x = x$1;
    def <init>(): Y = {
      Y.super.<init>();
      X$class./*X$class*/$init$(Y.this);
      ()
    }
  };
  abstract trait X$class extends  {
    def /*X$class*/$init$($this: X): Unit = {
      $this.X$_setter_$x_=(5);
      ()
    }
  }
}

All that stuff for Y you are going to have to implement by hand in Java. You need to define the field (x), the accessor method (also x), the setter method (X$_setter_$x_), and put the call to X$class.$init$ in your constructor.