1

I'm working on a project which has both scala and java code. I want to use a class written in scala in java code. Problem I'm having is that scala class has some self type dependencies. I don't know how to give them when creating new instance of that class from java.

trait Deps1 {
 def dep1 = println("dep1")
}

trait Deps2 {
 def dep2 = println("dep2")
}

class TestClass {
 this: Deps1 with Deps2 =>

 def test = {
   dep1
   dep2
 }
}

In scala if I'm to create instance of TestClass I can use new TestClass with Deps1 with Deps2 but I don't know how to do that in java code.

I'm using scala 2.9.2. Can anyone help me on this?

Chathurika Sandarenu
  • 1,368
  • 13
  • 25
  • I'd recommend using `javap` to understand what `.class` files are generated from this Scala source. I suspect you'll find it to be too much of a nuisance to work with from Java. – mergeconflict Jul 12 '12 at 05:36
  • Based on answers from Brain and Rex there are two main ways to get this working.
    Method 1:
    Creating class with all the dependencies in scala and using that (as mentioned by Rex) is the easiest I think.
    Method 2:
    In addition to that we can implement class directly in java as follows and use it.
    class TestClassWithDeps extends TestClass implements Deps1, Deps2 { public void dep1() { Deps1$class.dep1(this); } public void dep2() { Deps2$class.dep2(this); } }
    – Chathurika Sandarenu Jul 12 '12 at 07:10

3 Answers3

5

If the traits are at all complicated, it's best to let Scala handle them. Write a stub in Scala that the Java can instantitate:

class TestWithDeps extends TestClass with Deps1 with Deps2
Nikita Volkov
  • 42,792
  • 11
  • 94
  • 169
Rex Kerr
  • 166,841
  • 26
  • 322
  • 407
1

Scala traits are compiled to Java interfaces. So, in your Java code you are implementing the interface Deps1 for example. See this answer for example and details

For your code the the following Java code works:

class Test extends TestClass implements Deps1, Deps2{
   public void dep1(){
     Deps1$class.dep1(this);
   } 

   public void dep2(){
     Deps2$class.dep2(this);
   }

   public static void main(String []args){
     Test test = new Test();
     test.dep1();
     test.dep2();
   }

}

Running this gives:

dep1
dep2

Compile and run with the compiled Deps1, Deps2, and TestClass on the classpath and the scala-library jar like so javac -classpath .:scala-library.jar Test.java

Community
  • 1
  • 1
Brian
  • 20,195
  • 6
  • 34
  • 55
0

You are asking on how to create anonymous classes in Java mixing traits. This is simply not possible because in Java you cannot mix a trait, you can implement an interface, which contains no code.

If you reason a little bit about the concept of Scala Trait and how it could be implemented on the top of JVM valid bytecote keeping the compatibility with Java, you figure it out by yourself (I am not saying this this the exact way Scala treats traits, but is very similar)

  • A java interface is created
  • When the trait is mixed into a class, at compile time the "concrete" functions are physically copied by the compiler into the class.

This is the trick that allows Scala trait to contain concrete functions, but of course you need the source file to be a Scala one. Remember furthermore that when you create anonymous classes like :

val a = new MyClass extends A with B

The scala compiler physically generates an anonymous class for that (and apply the necessary transformation to mix traits). So, if you need to create an instance of MyClass extends A with B from Java, as Rex suggested the best way is to create a stub in Scala, and instanciate that from Java. The stub will be compiled by Scalac, which will correctly handle trait.

Edmondo
  • 19,559
  • 13
  • 62
  • 115