2016-12-16 4 views
3

Es scheint eine Feinheit bei der Verwendung der frühen Initialisersyntax zu geben.Frühe Initialisierung `neue {} mit SomeTrait` fehlgeschlagen

trait Base { def callMe = "callMe" } 
trait Proxy { this: Base => def call = s"proxied: $callMe" } 

val base1 = new Base { } // non-early init works 
val baseFail = new { } with Base // error: trait Base is abstract; cannot be instantiated 
val base2 = new { val n=1 } with Base // why does this fix the failure? 
val proxy = new { } with Base with Proxy // why doesn't this fail? 

Warum die baseFail Linie versagen, während die anderen val s nicht?

Die Fehlermeldung ist auch verwirrend - Ich versuche Base nicht nur zu instanziiert, es in mischte

Antwort

5

Wenn Sie new { } with Base schreiben, gibt es technisch keine frühen Definitionen. Nach dem SLS 5.1.6 sucht der Compiler für ein Muster wie folgt aus:

EarlyDefs   ::= `{' [EarlyDef {semi EarlyDef}] `}' `with' 
EarlyDef   ::= {Annotation} {Modifier} PatVarDef 

Obwohl es nicht explizit sagen, was passiert, wenn die Sequenzen von Definitionen leer ist, scheint es ihnen einfach zu entfernen, denn wenn Sie kompilieren val a = new { val x = 1 } with Base, Sie so etwas wie dies nach dem Parsing-Phase erhalten:

val a = { 
    final class $anon extends Base { 
    val x = _; 
    def <init>() = { 
     val x = 1; 
     super.<init>(); 
    () 
    } 
    }; 
    new $anon() 
} 

Aber wenn man die Klammern leer, man einfach erhalten:

val a = new Base() 

Welche krank ist egal, wie ist new Base.


Fassen wir zusammen:

ist eine anonyme Klasse, die erlaubt ist:

val base1 = new Base { } 

Vereinfacht zu new Base, die illegal ist:

val baseFail = new { } with Base 

ist eine richtige früh Definition (nicht leer), die erlaubt ist:

val base2 = new { val n=1 } with Base 

Vereinfacht zu new Base with Proxy die auch erlaubt ist:

val proxy = new { } with Base with Proxy 

new { } with Base { } auch kompiliert, aber es ist genau das gleiche wie new Base { }, also gibt es keinen Grund, es auf diese Weise zu schreiben.

1

Ich bin nicht sicher, aber die einfachste Erklärung, die ich von diesem Verhalten denken kann, ist, dass die leer früh. Initialisierer ist einfach weg optimiert, so ist es gleich val baseFail = new Base und val proxy = new Base with Proxy. new Base schlägt mit derselben Fehlermeldung fehl, und new Base with Proxy ist legal, da es eine anonyme Klasse ist. Wenn dem so ist, denke ich, dass es technisch ein Compiler-Bug ist, aber ein ziemlich kleiner.

Verwandte Themen