Search code examples
clojure

how to call 'final G.Run run = g.new Run()' in clojure


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();

Solution

  • 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)))