Comment la correspondance de modèles dans Scala est-elle implémentée au niveau du bytecode?
Est-ce comme une série de if (x instanceof Foo)
constructions, ou autre chose? Quelles sont ses implications en termes de performances?
Par exemple, étant donné le code suivant (extrait des pages 46 à 48 de Scala By Example ), à quoi eval
ressemblerait le code Java équivalent pour la méthode?
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 Je peux lire le bytecode Java, donc une représentation bytecode serait assez bonne pour moi, mais il serait probablement préférable que les autres lecteurs sachent à quoi cela ressemblerait en tant que code Java.
PPS Le livre Programming in Scala donne-t-il une réponse à cette question et à des questions similaires sur la manière dont Scala est implémentée? J'ai commandé le livre, mais il n'est pas encore arrivé.
la source
Réponses:
Le niveau bas peut être exploré avec un désassembleur mais la réponse courte est que c'est un tas de if / elses où le prédicat dépend du modèle
Il y a beaucoup plus que vous pouvez faire avec des modèles comme ou des modèles et des combinaisons comme "case Foo (45, x)", mais généralement ce ne sont que des extensions logiques de ce que je viens de décrire. Les modèles peuvent également avoir des gardes, qui sont des contraintes supplémentaires sur les prédicats. Il y a aussi des cas où le compilateur peut optimiser la correspondance de motifs, par exemple quand il y a un chevauchement entre les cas, il peut un peu fusionner les choses. Les modèles avancés et l'optimisation sont un domaine de travail actif dans le compilateur, alors ne soyez pas surpris si le code d'octet s'améliore considérablement par rapport à ces règles de base dans les versions actuelles et futures de Scala.
En plus de tout cela, vous pouvez écrire vos propres extracteurs personnalisés en plus ou à la place de ceux par défaut que Scala utilise pour les classes de cas. Si vous le faites, le coût de la correspondance de modèle est le coût de tout ce que fait l'extracteur. Un bon aperçu se trouve dans http://lamp.epfl.ch/~emir/written/MatchingObjectsWithPatterns-TR.pdf
la source
James (ci-dessus) l'a dit le mieux. Cependant, si vous êtes curieux, c'est toujours un bon exercice de regarder le bytecode démonté. Vous pouvez également appeler
scalac
avec l'-print
option, qui imprimera votre programme avec toutes les fonctionnalités spécifiques à Scala supprimées. C'est essentiellement Java dans les vêtements de Scala. Voici lascalac -print
sortie pertinente pour l'extrait de code que vous avez donné:la source
Depuis la version 2.8, Scala a l' annotation @switch . Le but est de s'assurer que la correspondance de modèle sera compilée dans tablewitch ou lookupswitch au lieu d'une série d'
if
instructions conditionnelles .la source
@switch
est plus efficace que la correspondance de motif classique. donc si tous les cas contiennent des valeurs constantes, vous devez toujours utiliser@switch
(car l'implémentation du bytecode sera la même que celle de javaswitch
au lieu de plusieurs if-else)