Wie wird der Mustervergleich in Scala auf Bytecode-Ebene implementiert?
Ist es wie eine Reihe von if (x instanceof Foo)
Konstrukten oder etwas anderes? Was sind die Auswirkungen auf die Leistung?
Wie würde beispielsweise der entsprechende Java-Code für die Methode angesichts des folgenden Codes (von Scala By Example, Seiten 46-48) eval
aussehen?
abstract class Expr
case class Number(n: Int) extends Expr
case class Sum(e1: Expr, e2: Expr) extends Expr
def eval(e: Expr): Int = e match {
case Number(x) => x
case Sum(l, r) => eval(l) + eval(r)
}
PS Ich kann Java-Bytecode lesen, daher wäre eine Bytecode-Darstellung für mich gut genug, aber wahrscheinlich wäre es für die anderen Leser besser zu wissen, wie es als Java-Code aussehen würde.
PPS Gibt das Buch Programmieren in Scala eine Antwort auf diese und ähnliche Fragen zur Implementierung von Scala? Ich habe das Buch bestellt, aber es ist noch nicht angekommen.
performance
scala
pattern-matching
bytecode
Esko Luontola
quelle
quelle
Antworten:
Das niedrige Level kann mit einem Disassembler erkundet werden, aber die kurze Antwort lautet, dass es sich um eine Reihe von if / elses handelt, bei denen das Prädikat vom Muster abhängt
Es gibt noch viel mehr, was Sie mit Mustern wie oder Mustern und Kombinationen wie "case Foo (45, x)" tun können, aber im Allgemeinen sind dies nur logische Erweiterungen dessen, was ich gerade beschrieben habe. Muster können auch Schutzvorrichtungen haben, die zusätzliche Einschränkungen für die Prädikate darstellen. Es gibt auch Fälle, in denen der Compiler den Mustervergleich optimieren kann, z. B. wenn sich die Fälle etwas überschneiden, kann dies zu einer gewissen Verschmelzung führen. Erweiterte Muster und Optimierungen sind ein aktiver Arbeitsbereich im Compiler. Seien Sie also nicht überrascht, wenn sich der Bytecode in aktuellen und zukünftigen Versionen von Scala gegenüber diesen Grundregeln erheblich verbessert.
Darüber hinaus können Sie zusätzlich zu oder anstelle der Standardextraktoren, die Scala für Fallklassen verwendet, eigene benutzerdefinierte Extraktoren schreiben. Wenn Sie dies tun, sind die Kosten für die Musterübereinstimmung die Kosten für alles, was der Extraktor tut. Eine gute Übersicht finden Sie unter http://lamp.epfl.ch/~emir/written/MatchingObjectsWithPatterns-TR.pdf
quelle
James (oben) sagte es am besten. Wenn Sie jedoch neugierig sind, ist es immer eine gute Übung, sich den zerlegten Bytecode anzusehen. Sie können auch
scalac
mit der-print
Option aufrufen, mit der Ihr Programm gedruckt wird, wobei alle Scala-spezifischen Funktionen entfernt wurden. Es ist im Grunde Java in Scalas Kleidung. Hier ist die relevantescalac -print
Ausgabe für das von Ihnen angegebene Code-Snippet:quelle
Seit Version 2.8 hat Scala die Annotation @switch . Ziel ist es sicherzustellen, dass der Mustervergleich anstelle einer Reihe von bedingten Anweisungen in einen Tabellen- oder Suchschalter kompiliert wird
if
.quelle
@switch
ist effizienter als der reguläre Mustervergleich. Wenn also alle Fälle konstante Werte enthalten, sollten Sie immer verwenden@switch
(da die Bytecode-Implementierung dieselbe ist wie bei Javaswitch
anstelle vieler if-else)