W jaki sposób dopasowywanie wzorców w Scali jest realizowane na poziomie kodu bajtowego?
Czy to jak seria if (x instanceof Foo)
konstrukcji, czy coś innego? Jakie są jego konsekwencje dla wydajności?
Na przykład, biorąc pod uwagę następujący kod (ze stron Scala By Przykład, strony 46-48), jak wyglądałby odpowiednik kodu Java dla tej eval
metody?
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 Potrafię czytać kod bajtowy Javy, więc reprezentacja kodu bajtowego byłaby dla mnie wystarczająca, ale prawdopodobnie byłoby lepiej, aby inni czytelnicy wiedzieli, jak będzie wyglądał kod Java.
PPS Czy książka Programming in Scala zawiera odpowiedź na to i podobne pytania dotyczące implementacji Scali? Zamówiłem książkę, ale jeszcze nie dotarła.
performance
scala
pattern-matching
bytecode
Esko Luontola
źródło
źródło
Odpowiedzi:
Niski poziom można zbadać za pomocą dezasemblera, ale krótka odpowiedź jest taka, że jest to zbiór if / elses, w których predykat zależy od wzorca
Jest dużo więcej rzeczy, które możesz zrobić z wzorcami lub wzorcami i kombinacjami, takimi jak „case Foo (45, x)”, ale ogólnie są to tylko logiczne rozszerzenia tego, co właśnie opisałem. Wzorce mogą również mieć osłony, które są dodatkowymi ograniczeniami predykatów. Istnieją również przypadki, w których kompilator może zoptymalizować dopasowanie wzorców, np. Gdy zachodzi pewne nakładanie się przypadków, może to nieco połączyć. Zaawansowane wzorce i optymalizacja są aktywnym obszarem pracy kompilatora, więc nie zdziw się, jeśli kod bajtowy znacznie się poprawi w stosunku do tych podstawowych reguł w obecnych i przyszłych wersjach Scali.
Oprócz tego możesz napisać własne niestandardowe ekstraktory oprócz lub zamiast tych domyślnych, których Scala używa dla klas przypadków. Jeśli tak, to koszt dopasowania wzorca jest kosztem tego, co robi ekstraktor. Dobry przegląd można znaleźć w http://lamp.epfl.ch/~emir/written/MatchingObjectsWithPatterns-TR.pdf
źródło
James (powyżej) powiedział to najlepiej. Jeśli jednak jesteś ciekawy, zawsze dobrym ćwiczeniem jest przyjrzenie się zdemontowanemu kodowi bajtowemu. Możesz także wywołać
scalac
z-print
opcją, która wydrukuje twój program z usuniętymi wszystkimi funkcjami specyficznymi dla Scala. W zasadzie to Java w ubraniach Scali. Oto odpowiedniescalac -print
dane wyjściowe dla podanego fragmentu kodu:źródło
Od wersji 2.8 Scala ma adnotację @switch . Celem jest zapewnienie, że dopasowywanie wzorców zostanie skompilowane do tablewitch lub lookupswitch zamiast serii
if
instrukcji warunkowych .źródło
@switch
jest bardziej wydajne niż zwykłe dopasowywanie wzorców. więc jeśli wszystkie przypadki zawierają stałe wartości, powinieneś zawsze używać@switch
(ponieważ implementacja kodu bajtowego będzie taka sama jak w javaswitch
zamiast wielu if-else)