2

I'm looking for help on calling the scala compiler in clojure. How would this line translate to clojure?

final G.Run run = g.new Run();
zcaudate
  • 13,998
  • 7
  • 64
  • 124

1 Answers1

3

Inner classes in Java are just a syntactic sugar for classes that get passes the outer class reference in their (syntactic) constructor.

I am not aware of any syntactic sugar for calling such constructors in Clojure. But we can examine how this Java language syntactic sugar is translated into generated JVM bytecode.

Let's take this example:

package test;

public class Outer {
    public String oName;

    public Outer(String name) {
        this.oName = name;
    }

    public class Inner {
        public String iName;
        public Inner(String name) {
            this.iName = name;
        }
    }
}

When we compile this code and check the generated bytecode we can see the following syntactic constructor has been generated in test.Outer.Inner class (use javap -verbose Outer\$Inner.class command):

public test.Outer$Inner(test.Outer, java.lang.String);
    descriptor: (Ltest/Outer;Ljava/lang/String;)V
    flags: ACC_PUBLIC
    Code:
      stack=2, locals=3, args_size=3
         0: aload_0
         1: aload_1
         2: putfield      #1                  // Field this$0:Ltest/Outer;
         5: aload_0
         6: invokespecial #2                  // Method java/lang/Object."<init>":()V
         9: aload_0
        10: aload_2
        11: putfield      #3                  // Field iName:Ljava/lang/String;
        14: return
      LineNumberTable:
        line 12: 0
        line 13: 9
        line 14: 14

In Java we don't use this constructor directly but a call to it is generated by Java compiler.

So this code in Java:

Outer outer = new Outer("outer");
Outer.Inner inner = outer.new Inner("inner");

is compiled to something like this in JVM bytecode:

Outer outer = new Outer("outer");
Outer.Inner inner = new Outer.Inner(outer, "inner");

We can leverate this in Clojure and translate JVM bytecode version to Clojure code:

(import '[test Outer Outer$Inner])

(let [outer (Outer. "outer")
      inner (Outer$Inner. outer "inner")]
  (println "Outer" (.-name outer))
  (println "Inner" (.-name inner)))
Piotrek Bzdyl
  • 12,965
  • 1
  • 31
  • 49
  • 1
    ah yes. `(Global$Run. g)` works. but now I'm getting a `object scala in compiler mirror not found` error. – zcaudate Sep 07 '18 at 07:25
  • 1
    I guess Scala compiler does something different in the generated bytecode. You could see with `javap` what is emitted for the equivalent code in Scala. – Piotrek Bzdyl Sep 07 '18 at 12:09
  • Oh, I misread your comment. So it seems the code to create an instance of the inner class works from Clojure but now you are seeing another issue with invoking Scala compiler. – Piotrek Bzdyl Sep 08 '18 at 12:44