65

I guess it is not possible to invoke methods implemented in Scala traits from Java, or is there a way?

Suppose I have in Scala:

trait Trait {
  def bar = {}
}

and in Java if I use it as

class Foo implements Trait {
}

Java complains that Trait is not abstract and does not override abstract method bar() in Trait

Jus12
  • 17,824
  • 28
  • 99
  • 157
  • 1
    Is this an error? Shouldn't the line look like "Java complains that **Foo** is not abstract and does not override abstract method bar() in Trait" ? – Ravi Sanwal Sep 30 '15 at 22:07

2 Answers2

137

Answer

From Java perspective Trait.scala is compiled into Trait interface. Hence implementing Trait in Java is interpreted as implementing an interface - which makes your error messages obvious. Short answer: you can't take advantage of trait implementations in Java, because this would enable multiple inheritance in Java (!)

How is it implemented in Scala?

Long answer: so how does it work in Scala? Looking at the generated bytecode/classes one can find the following code:

interface Trait {
    void bar();
}

abstract class Trait$class {
    public static void bar(Trait thiz) {/*trait implementation*/}
}

class Foo implements Trait {
    public void bar() {
        Trait$class.bar(this);  //works because `this` implements Trait
    }
}
  • Trait is an interface
  • abstract Trait$class (do not confuse with Trait.class) class is created transparently, which technically does not implement Trait interface. However it does have a static bar() method taking Trait instance as argument (sort of this)
  • Foo implements Trait interface
  • scalac automatically implements Trait methods by delegating to Trait$class. This essentially means calling Trait$class.bar(this).

Note that Trait$class is neither a member of Foo, nor does Foo extend it. It simply delegates to it by passing this.

Mixing in multiple traits

To continue the digression on how Scala works... That being said it is easy to imagine how mixing in multiple traits works underneath:

trait Trait1 {def ping(){}};
trait Trait2 {def pong(){}};
class Foo extends Trait1 with Trait2

translates to:

class Foo implements Trait1, Trait2 {
  public void ping() {
    Trait1$class.ping(this);    //works because `this` implements Trait1
  }

  public void pong() {
    Trait2$class.pong(this);    //works because `this` implements Trait2
  }
}

Multiple traits overriding same method

Now it's easy to imagine how mixing in multiple traits overriding same method:

trait Trait {def bar(){}};
trait Trait1 extends Trait {override def bar(){}};
trait Trait2 extends Trait {override def bar(){}};

Again Trait1 and Trait2 will become interfaces extending Trait. Now if Trait2 comes last when defining Foo:

class Foo extends Trait1 with Trait2

you'll get:

class Foo implements Trait1, Trait2 {
    public void bar() {
        Trait2$class.bar(this); //works because `this` implements Trait2
    }
}

However switching Trait1 and Trait2 (making Trait1 to be last) will result in:

class Foo implements Trait2, Trait1 {
    public void bar() {
        Trait1$class.bar(this); //works because `this` implements Trait1
    }
}

Stackable modifications

Now consider how traits as stackable modifications work. Imagine having a really useful class Foo:

class Foo {
  def bar = "Foo"
}

which you want to enrich with some new functionality using traits:

trait Trait1 extends Foo {
  abstract override def bar = super.bar + ", Trait1"
}

trait Trait2 extends Foo {
  abstract override def bar = super.bar + ", Trait2"
}

Here is the new 'Foo' on steroids:

class FooOnSteroids extends Foo with Trait1 with Trait2

It translates to:

Trait1

interface Trait1 {
  String Trait1$$super$bar();
  String bar();
}
abstract class Trait1$class {
  public static String bar(Trait1 thiz) {
    // interface call Trait1$$super$bar() is possible
    // since FooOnSteroids implements Trait1 (see below)
    return thiz.Trait1$$super$bar() + ", Trait1";
  }
}

Trait2

public interface Trait2 {
  String Trait2$$super$bar();
  String bar();
}
public abstract class Trait2$class {
  public static String bar(Trait2 thiz) {
    // interface call Trait2$$super$bar() is possible
    // since FooOnSteroids implements Trait2 (see below)
    return thiz.Trait2$$super$bar() + ", Trait2";
  }
}

FooOnSteroids

class FooOnSteroids extends Foo implements Trait1, Trait2 {
  public final String Trait1$$super$bar() {
    // call superclass 'bar' method version
    return Foo.bar();
  }

  public final String Trait2$$super$bar() {
    return Trait1$class.bar(this);
  }

  public String bar() {
    return Trait2$class.bar(this);
  }      
}

So the whole stack invocations are as follows:

  • 'bar' method on FooOnSteroids instance (entry point);
  • Trait2$class's 'bar' static method passing this as argument and returning a concatenation of 'Trait2$$super$bar()' method call and string ", Trait2";
  • 'Trait2$$super$bar()' on FooOnSteroids instance which calls ...
  • Trait1$class's 'bar' static method passing this as argument and returning a concatenation of 'Trait1$$super$bar()' method call and string ", Trait1";
  • 'Trait1$$super$bar' on FooOnSteroids instance which calls ...
  • original Foo's 'bar' method

And the result is "Foo, Trait1, Trait2".

Conclusion

If you've managed to read everything, an answer to the original question is in the first four lines...

Bruno Bieth
  • 2,317
  • 20
  • 31
Tomasz Nurkiewicz
  • 334,321
  • 69
  • 703
  • 674
  • 4
    Well... it is missing how `abstract override` works, but it's pretty good otherwise. :-) – Daniel C. Sobral Oct 03 '11 at 20:33
  • 1
    Thanks! And a typo: You wrote `class Foo implements Trait1, Trait2` again when you intended to switch Trait1 and Trait2. – KajMagnus May 14 '12 at 09:32
  • 1
    @KajMagnus: this part was added by *Tvaroh*, maybe he can fix it? – Tomasz Nurkiewicz May 14 '12 at 09:39
  • @TomaszNurkiewicz Sorry I misread the answer. I think it's correct as is. (Didn't notice that the relevant code snippet is actually Java code not Scala code). – KajMagnus May 14 '12 at 10:54
  • +1 As a compiler developer (and enthusiast), this information was really helpful. Now I don't need to reverse-engineer it myself. Thanks a lot! :3 – paulotorrens Dec 08 '13 at 07:26
  • This is very good answer, but I see it was answered in 2011, before Java 8 that supports [default method](https://docs.oracle.com/javase/tutorial/java/IandI/defaultmethods.html). What's the implementation after Java 8? – Wins Jan 31 '22 at 01:23
2

It's indeed not abstract since bar is returning an empty Unit (a kind of NOP). Try:

trait Trait {
  def bar: Unit
}

Then bar will be a Java abstract method returning void.

paradigmatic
  • 40,153
  • 18
  • 88
  • 147
  • That is my question. If I have a complex method implemented in `bar` of `Trait`, I would like to reuse it in a Java class, as I can do in Scala. But I guess this is not possible. The only fix seems to be to convert Trait into an abstract class. – Jus12 Oct 03 '11 at 16:38
  • Yes. You should make it an abstract class. Or even better, keep it as a trait, but add an abstract class which just extends it (to have a Java binding). Then you can extend the trait from Scala or inherit from the abstract class from Java. – paradigmatic Oct 03 '11 at 16:42
  • Yes, though this will eat up the only available spot for Java abstract classes. – Jus12 Oct 03 '11 at 16:48
  • 1
    Other solution is to use composition/aggregation. You could either use the generated static method (see Tomasz answer) or write an object suitable for nice Java interaction. – paradigmatic Oct 03 '11 at 16:51