为什么Scala的同伴对象编成两个班(Java和.NET编译器)?编译器、同伴、对象、两个

2023-09-04 09:53:33 作者:我成长了

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

这片code会被编译成Java字节code,如果我反编译它,那么相应的Java code是类似这样的:

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;
/*    */   }
/*    */ }

它编成两个班,如果我用Scala.net编译器,它会被编译成MSIL code,以及相当于C#code是这样的:

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.

为什么斯卡拉编译器(一个用于Java和一个用于.NET)做到这一点? 为什么它不只是调用静态规则方法println方法?

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?

推荐答案

据了解,在Scala中,一个对象实际上是一等公民是很重要的:它是可传递围绕任何其他对象的实际实例。 举例:

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 )

不像静态方法,我们单独的对象具有完全多态beheviour。 DoSomething的确实叫我们被覆盖的你好再见的方法,而不是默认的实现方式:

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

因此​​,对象的实施必然是一个正确的类。但对于与Java的互操作性, 编译器还生成刚着类的唯一实例(模块$ )的静态方法(参见JavaTrueRing.rule())。 这样一来,Java程序可以访问单一对象的方法,作为一个正常的静态方法。 现在你可能会问,为什么斯卡拉不能把静态方法转发在同一类的实例方法。这将使我们是这样的:

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

我认为,最主要的原因,这不能简单是因为在JVM可以在同一个类中没有一个实例方法和静态方法问心无愧相同的签名。 可能有其他原因,但。

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.