1

Suppose I have:

trait A{
    println("A")
}

Now I want to inherit this trait in my Java code:

class B implements A {}

It looks like constructor of trait A is not going to be executed. Is it possible to force constructor of trait A to be executed in scope of class B?

Dmitry Bespalov
  • 5,179
  • 3
  • 26
  • 33
  • 1
    Related: [Using Scala traits with implemented methods in Java](http://stackoverflow.com/q/7637752/1065197) – Luiggi Mendoza Jul 03 '15 at 17:40
  • @LuiggiMendoza Related question/answer you've proposed don't cover the case with trait's constructor. I'm interesting particularly in trait's constructor invocation here. – Dmitry Bespalov Jul 03 '15 at 17:59
  • To the best of my knowledge, you are not allowed to have constructors in interfaces in Java. I think for the same reason you cannot do what you are asking here. – marios Jul 03 '15 at 18:11
  • If you **read** the link in that comment, you will find this: **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 (!)**. And that answers your question: you cannot do what you want, check for another alternative. – Luiggi Mendoza Jul 03 '15 at 19:23
  • @LuiggiMendoza I've *read* it, and completely understood the topic. This question is about trait's *constructor*, not any other regular method, which has a name, and I could call it like `A$class.something`. I suppose, if there is abilities to call trait's regular methods in java's successor, then there should be some way to call a constructor as method as well... – Dmitry Bespalov Jul 05 '15 at 07:32
  • If you understand the topic *as you say*, then it means you should understand both Scala and Java parts, and in Java interfaces don't have a constructor, so what you're trying to do is basically impossible. Instead the *trick* explained by @Alexey seems a better design proposition. I won't rely on decompiled sources because they may change with time. – Luiggi Mendoza Jul 05 '15 at 07:37

2 Answers2

3

That would become something like:

public interface A {

}

public abstract class A$class {
    public static void $init$(A $this) {
        Predef..MODULE$.println((Object)"A");
    }
}

using a decompiler. Java speaking, that is:

public class AImpl implements A {}
public class User {
  public User() {
    A a = new AImpl();
    A$class.$init$(a);
  }
}
bjfletcher
  • 11,168
  • 4
  • 52
  • 67
  • So, you talking about: move you code in trait's constructor into `init` method, then call it directly from trait's constructor, and in java's successor as well, right? Because I haven't seen an `init` method in that trait when was implementing it in java's class. – Dmitry Bespalov Jul 05 '15 at 07:22
  • Yes except... no moving is needed because the Java code I gave above is what Scala compiler would produce with your code. I was just answering your question "Is it possible to force constructor of trait A to be executed in scope of class B" and the code I gave in answer was how to do that. If you can add more Scala code to it, then the other answer (from Alexey) would be the way to go. – bjfletcher Jul 05 '15 at 09:14
  • Are you sure, compiler produce `init` method for trait's constuctor? I'm asking because I didn't found that when was trying to write such code... – Dmitry Bespalov Jul 06 '15 at 08:52
  • Did you include the dollar signs? See updated answer where I've expanded on the Java code. – bjfletcher Jul 06 '15 at 11:46
3

The most reasonable way to get a Java class implementing a trait which has a constructor and/or non-abstract members is to extend the trait with a class in Scala, then extend this class in Java:

// AbstractA.scala
abstract class AbstractA extends A 

// B.java
class B extends AbstractA

This way the Scala compiler takes care of all the stuff you have to do manually in Java otherwise, as you can see in bjfletcher's answer.

Alexey Romanov
  • 167,066
  • 35
  • 309
  • 487