Warum kann eine Methode, die eine Einheit zurückgibt, mit einer Methode überschrieben werden, die einen String zurückgibt, wenn Rückgabetypen nicht explizit angegeben werden?

11

Ich habe die Codebeispiele aus dem Kapitel über Merkmale in der Programmierung in Scala Edition1 https://www.artima.com/pins1ed/traits.html durchgearbeitet

und stieß wegen meines Tippfehlers auf ein komisches Verhalten. Während zwingende Methode eines Merkmal unter Code - Schnipsel gibt keine Kompilierung - Fehler , obwohl die Rückgabetypen der überschriebenen Methode unterscheidet Unitvs String. Beim Aufrufen der Methode für ein Objekt wird Unit zurückgegeben, es wird jedoch nichts gedruckt.

trait Philosophical {
    def philosophize = println("I consume memory, therefore I am!")
}

class Frog extends Philosophical {
  override def toString = "green"
  override def philosophize = "It aint easy to be " + toString + "!"
}

val frog = new Frog
//frog: Frog = green

frog.philosophize
// no message printed on console

val f = frog.philosophize
//f: Unit = ()

Wenn ich jedoch den expliziten Rückgabetyp in der überschriebenen Methode gebe, wird ein Kompilierungsfehler ausgegeben:

class Frog extends Philosophical {
  override def toString = "green"
  override def philosophize: String = "It aint easy to be " + toString + "!"
}
         override def philosophize: String = "It aint easy to be " + toString +
                      ^
On line 3: error: incompatible type in overriding
       def philosophize: Unit (defined in trait Philosophical);
        found   : => String
        required: => Unit

Kann mir jemand erklären, warum im ersten Fall kein Kompilierungsfehler vorliegt.

Shanil
quelle
Der Compiler hat einen gültigen Hinweis gedruckt, dass Sie versuchen, eine Methode mit einem anderen Ergebnistyp zu überschreiben.
Andriy Plokhotnyuk
Ja, aber meine Frage ist, warum es im ersten Fall durch den Compiler gekommen ist
Shanil
1
Als Faustregel gilt, dass Rückgabetypen immer explizit angegeben werden müssen (insbesondere bei öffentlichen APIs). Die Typinferenz eignet sich hervorragend für lokale Variablen, sonst nichts.
Luis Miguel Mejía Suárez

Antworten:

8

Wenn der erwartete Typ ist Unit, kann jeder Wert akzeptiert werden :

Wert verwerfen

Wenn eein Werttyp vorhanden ist und der erwartete Typ lautet Unit, ewird er durch Einbetten in den Begriff in den erwarteten Typ konvertiert { e; () }.

Alexey Romanov
quelle
6

Meine Frage ist, warum es im 1. Fall durch den Compiler gekommen ist

Wenn Sie den Rückgabetyp nicht explizit angegeben haben, wurde er von dem Typ abgeleitet, den er für den benötigt override er funktioniert.

Das stellte sich heraus Unit .

Da StringWerte (der Wert des Ausdrucks, aus dem der Funktionskörper besteht) zugewiesen werden können, Unitist der Compiler zufrieden.

Thilo
quelle
1
Was ich jetzt jedoch wissen möchte, ist, warum der explizite Rückgabetyp String abgelehnt wurde. In Java (und ich denke , in Scala, auch), dürfen Sie verengen den Rückgabetyp beim Überschreiben. Wenn beispielsweise die übergeordnete Methode zurückgegeben wird Number, können Sie zurückkehren Integer. Vielleicht void/ Unitist etwas Besonderes.
Thilo
1
Dies kompiliert zum Beispiel:trait Philosophical { def philosophize : Number = 1 } class Frog extends Philosophical { override def philosophize : Integer = 2 }
Thilo
2
Sie können den Rückgabetyp auf einen Untertyp eingrenzen. Sie können es jedoch nicht auf einen Typ eingrenzen, der nur implizit in den Rückgabetyp der überschriebenen Methode konvertiert werden kann. Stringto Unitist eher wie das zweite, auch wenn es nicht genau ist das ist.
Alexey Romanov
2
Auf Bytecode-Ebene gibt es auch keinen verengenden Rückgabetyp, es gibt tatsächlich zwei Methoden in Frog: def philosophize : Integerund def philosophize : Number. Der zweite überschreibt tatsächlich diePhilosophical Methode Methode der (und ruft die erste auf). Das gleiche könnte sicherlich für void/ alles andere getan werden , die Designer haben einfach beschlossen, es nicht zu tun.
Alexey Romanov
2
1. Java macht dasselbe. 2. Ja, in Bytecode können Sie. Siehe z . B. stackoverflow.com/questions/18655541/… und stackoverflow.com/questions/58065680/… .
Alexey Romanov