Why is a Scala companion object compiled into two classes(both Java and .NET compilers)?
Asked Answered
L

3

12
object ScalaTrueRing {
  def rule = println("To rule them all")
}

this piece of code will be compiled into java byte code, if I decompile it, then the equivalent Java code is similar to this:

public final class JavaTrueRing
{
  public static final void rule()
  {
    ScalaTrueRing..MODULE$.rule();
  }
}


/*    */ public final class JavaTrueRing$
/*    */   implements ScalaObject
/*    */ {
/*    */   public static final  MODULE$;
/*    */ 
/*    */   static
/*    */   {
/*    */     new ();
/*    */   }
/*    */ 
/*    */   public void rule()
/*    */   {
/* 11 */     Predef..MODULE$.println("To rule them all");
/*    */   }
/*    */ 
/*    */   private JavaTrueRing$()
/*    */   {
/* 10 */     MODULE$ = this;
/*    */   }
/*    */ }

it's compiled into two classes, and if I use Scala.net compiler, it'll be compiled into MSIL code, and the equivalent C# code is like this:

public sealed class ScalaTrueRing
{
    public static void rule()
    {
        ScalaTrueRing$.MODULE$.rule();
    }
}

[Symtab]
public sealed class ScalaTrueRing$ : ScalaObject
{
    public static ScalaTrueRing$ MODULE$;
    public override void rule()
    {
        Predef$.MODULE$.println("To rule them all");
    }
    private ScalaTrueRing$()
    {
        ScalaTrueRing$.MODULE$ = this;
    }
    static ScalaTrueRing$()
    {
        new ScalaTrueRing$();
    }
}

It's also compiled into two classes.

Why do Scala compilers(the one for Java and the one for .NET) do this? Why does not it just call the println method in the static rule method?

Luckett answered 8/10, 2012 at 14:40 Comment(2)
So, where does the class JavaTrueRing$ comes from?Dishcloth
@The Elite Gentleman it's real name is ScalaTrueRing$, I changed the name to explicitly show that it's java code. I decompiled the class file and got that.Galla
S
13

It is important to understand that in scala, an object actually is a first class citizen: it is an actual instance that can be passed around as any other object. By example:

trait Greetings {
  def hello() { println("hello") }
  def bye() { println("bye") }
}

object FrenchGreetings extends Greetings {
  override def hello() { println("bonjour") }
  override def bye() { println("au revoir") }
}

def doSomething( greetings: Greetings ) {
  greetings.hello()
  println("... doing some work ...")
  greetings.bye()
}

doSomething( FrenchGreetings )

Unlike with static methods, our singleton object has full polymorphic beheviour. doSomething will indeed call our overriden hello and bye methods, and not the default implementations:

bonjour
... doing some work ...
au revoir

So the object implementation must necessarily be a proper class. But for interoperability with java, the compiler also generates static methods that just forward to the unique instance (MODULE$) of the class (see JavaTrueRing.rule()). This way, a java program can access the methods of the singleton object as a normal static method. Now you might ask why scala does not put the static method forwarders in the same class as the instance methods. This would give us something like:

public final class JavaTrueRing implements ScalaObject {
  public static final  MODULE$;

  static {
    new JavaTrueRing();
  }

  public void rule() {
    Predef.MODULE$.println("To rule them all");
  }

  private JavaTrueRing() {
    MODULE$ = this;
  }

  // Forwarders
  public static final void rule() {
    MODULE$.rule();
  }  
}

I believe that the main reason why this can't be as simple is because in the JVM you cannot have in the same class an instance method and a static method wth the same signature. There might be other reasons though.

Sadie answered 8/10, 2012 at 15:55 Comment(0)
K
3

Paraphrasing from "Programming in Scala" - Because a scala companion object (singleton object) is more than just a holder of static methods. By being an instance of a different Java class, it allows the developer to extend singleton objects and mix-in traits. This cannot be done with static methods.

Kerrykersey answered 8/10, 2012 at 15:37 Comment(0)
G
1

This Blog entry "A Look at How Scala Compiles to Java" should answer your question

Typically ClassName$.class are results of inner classes - Scala is obviously slightly different.

Gnni answered 8/10, 2012 at 14:45 Comment(1)
that blog post explains what Scala compiler does, but it does not explain why. Why does not Scala compiler just call the println method in the static rule method?Galla

© 2022 - 2024 — McMap. All rights reserved.