4

I have the following scala code

package x.y

package object config {

  type SomeType = AnotherType[YetAnotherOne]
}

The following is what JDGUI makes of it in Java

package x.y.config;

import scala.reflect.ScalaSignature;

@ScalaSignature(bytes="\006\001...")
public final class package {}

And...

package x.y.config;

public final class package$
{
  public static final  MODULE$;

  static
  {
    new ();
  }

  private package$()
  {
    MODULE$ = this;
  }
}

I have no problem with the disappearance of the type definition(I expect that scalac does away with it)

I do wish to know specifically what the following is:

static
{
  new ();
}

The MODULE$ gets explained here.

Thing is, when I cut and paste the Java code into my IDE it does not compile. Neither the non-typed public static final MODULE$; nor the new (); do.

Is it just some decompiling misalignment? Am I missing something?

What is going on here?


Edit:

as per request:

javap -c -l -private package\$.class
Compiled from "package.scala"
public final class x.y.config.package$ {
  public static final x.y.config.package$ MODULE$;

  public static {};
    Code:
       0: new           #2                  // class x/y/config/package$
       3: invokespecial #12                 // Method "<init>":()V
       6: return

  private x.y.config.package$();
    Code:
       0: aload_0
       1: invokespecial #13                 // Method java/lang/Object."<init>":()V
       4: aload_0
       5: putstatic     #15                 // Field MODULE$:Lx/y/config/package$;
       8: return
    LineNumberTable:
      line 9: 0
    LocalVariableTable:
      Start  Length  Slot  Name   Signature
          0       9     0  this   Lx/y/config/package$;
}
Community
  • 1
  • 1
Yaneeve
  • 4,751
  • 10
  • 49
  • 87

2 Answers2

3

I'm not a scala expert, but it seems normal to me, as "object" define a singleton object. See http://docs.scala-lang.org/tutorials/tour/singleton-objects.html

Alexandre Cartapanis
  • 1,513
  • 3
  • 15
  • 19
  • I know they do, I was wondering exactly how, which is how I came up with the code above... – Yaneeve Jan 20 '16 at 17:26
  • Maybe the use of a java decompiler to decompile scala code is not a good idea... generated bytecode is maybe slightly different, still based on the same instruction – Alexandre Cartapanis Jan 20 '16 at 17:31
  • I would guess that Java -> bytecode is a [bijective](https://en.wikipedia.org/wiki/Bijection) function – Yaneeve Jan 20 '16 at 17:44
  • 1
    Java tools are not likely to interpret Scala mangled names correctly. `package$` looks like a nested class with an empty name, normally `Foo$Bar`. – som-snytt Jan 20 '16 at 18:05
  • 1
    @Yaneeve: Java has features JVM bytecode has not (most notably generics, but also lambdas, anonymous classes) and JVM bytecode has features Java doesn't (most notably `GOTO`, but also `invokedynamic`). – Jörg W Mittag Jan 20 '16 at 19:45
  • Illuminating! (Though concerning erasure of generics, I personally don't count that in the Java -> bytcode transform as it is _sort of_ pre-processed... never mind that though). Also, armed with the new insight I found this [answer](http://stackoverflow.com/a/13381258/101715) that points out that Java is not generated by scalac, but that the final result is bytecode. Very interesting... – Yaneeve Jan 21 '16 at 07:45
  • I suspect @som-snytt nailed it, and your decompiler is (incorrectly) inferring `package$` to be an inner class with an empty simple name. Ideally, a decompiler should use the inner type tables to identify inner classes, as Procyon and CFR do, as `$` is a perfectly valid identifier character in Java. – Mike Strobel Jan 21 '16 at 11:01
  • If you or @som-snytt or somebody else would like to draft that into a more explicit answer, and perhaps even point to a method of decompiling scala code - _correctly_, I code accept and upvote. – Yaneeve Jan 21 '16 at 12:01
  • The standard REPL has a `:javap` command with enhancements such as support for showing anon functions and `DelayedInit` bodies. The problem is that much backend code gen changes over time, so it's maintenance to keep the tool up to date. I took some of that out again in 2.12 because of all the changes for java 8. – som-snytt Jan 22 '16 at 00:00
  • Thanks for the info. Does that mean that the command will not support 2.12? – Yaneeve Jan 24 '16 at 07:01
0

Following the interesting comments under @acartapanis's answer I had found the following decompilation

package org.cakesolutions.scala.basic;

public final class EmptyObject$
{
    public static final EmptyObject$ MODULE$;

    static {
        new EmptyObject$();
    }

    private EmptyObject$() {
        MODULE$ = this;
    }
}

which does make more sense...

The complete blog: Scala Dissection: Basic Types is very interesting and informative. I would like also to include the following quote:

For Scala code (and other JVM languages like Kotlin) I found that Procyon decompiler is really good and we'll stick to it in this series. Procyon is one of the 5 decompilers supported by ByteCode Viewer (among DJ-GUI/Core, CFR, Fernflower and Krakatau)

Bear in mind that decompilers aren't perfect and are prone to generate Java code that isn't compilable in the first try

Yaneeve
  • 4,751
  • 10
  • 49
  • 87