If I have the following Scala class:
abstract class MyOrdered extends Ordered[MyOrdered] {
def id: Int
def compare(that : MyOrdered) : Int =
if (that==null) 1 else (id-that.id)
}
Then I only need to define the id method in Scala to get a concrete class. But if I try to extend it in Java, the compiler says that all the concrete methods of Ordered are missing. So, does that mean that the Scala compiler is only putting the implementation of the concrete methods of Ordered in concrete Scala classes?
This seems very wasteful, because I could have dozens of concrete classes implementing MyOrdered, and they would all get a copy of the same code, when in fact it would be enough to just put it directly in the base class MyOrdered. Also, this makes it very difficult to create a Java-friendly Scala API. Is there any way to force the Scala compiler to put the method definitions where it should have done so anyway, apart from making the class concrete by using dummy method implementations?
Even funnier is declaring a concrete method final in a Scala trait. In that case, it is still not implemented in an abstract Scala class that extends the trait, but it cannot be implemented in a Java class that extends the abstract Scala class because it is flagged as final. This is definitely a compiler bug. Final abstract methods make no sense, even if they are legal in the JVM, apparently.
Scala 2.9.1.RC1
Let me introduce you to our friend
:javap
in the REPL, which can be useful for diagnosing errors. First, we define the class,And then ask to see the JVM bytecode,
We see that scalac actually generates methods in
MyOrdered
corresponding to those concrete ones in traitOrdered
. For example, the>
method gets translated to$greater
and basically just callsscala/math/Ordered$class.$greater
. If we like, we can now look up the bytecode for concrete trait definitions,Finally, let's test your hypothesis that a subclass
M
ofMyOrdered
gets a full copy of all the methodsNope, it looks like there's no code duplication here.
To conclude,
Scalac does some magic with traits with concrete methods, so don't try to inherit from them in Java. Abstract classes should be OK.
The JVM doesn't natively support symbolic method names, Scala singleton objects, nor traits with concrete methods, so the Scala compiler needs to do some translation, and uses the reserved symbol $.
If you're still having problems with Java interop, hopefully
:javap
will help you in diagnosing the specific problem.Note: that latest commit for Scal 2.12.x (August 2016) might optimize things a bit in
compiler/scala/tools/nsc/backend/jvm
: