Question

Comment est mise en correspondance de modèle à Scala mis en œuvre au niveau du bytecode?

Est-ce comme une série de constructions if (x instanceof Foo), ou autre chose? Quelles sont ses implications sur les performances?

Par exemple, étant donné le code suivant (de Scala Par exemple pages 46-48), comment le code Java équivalent pour la méthode eval ressembler?

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)
}

P.S. Je peux lire bytecode Java, donc une représentation bytecode serait assez bon pour moi, mais probablement il serait préférable pour les autres lecteurs de savoir comment il ressemblerait code Java.

P.P.S. Est-ce que le livre Programmation à Scala donner une réponse à cela et des questions similaires sur la façon dont Scala est implémenté? J'ai commandé le livre, mais il n'a pas encore arrivé.

Était-ce utile?

La solution

Le faible niveau peut être exploré avec un désassembleur mais la réponse courte est que c'est un tas de si / ELSES où le prédicat dépend du modèle

case Sum(l,r) // instance of check followed by fetching the two arguments and assigning to two variables l and r but see below about custom extractors 
case "hello" // equality check
case _ : Foo // instance of check
case x => // assignment to a fresh variable
case _ => // do nothing, this is the tail else on the if/else

Il y a beaucoup plus que vous pouvez faire avec des motifs similaires ou des modèles et des combinaisons comme « cas Foo (45, x) », mais en général ce ne sont que des extensions logiques de ce que je viens de décrire. Les modèles peuvent aussi avoir des gardes, qui sont des contraintes supplémentaires sur les prédicats. Il y a aussi des cas où le compilateur peut optimiser pattern matching, quand il y a par exemple un certain chevauchement entre les cas, il peut coalescer les choses un peu. modèles et d'optimisation sont une zone active de travail dans le compilateur, donc ne soyez pas surpris si le code d'octets améliore considérablement sur 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 au lieu de ceux par défaut Scala utilise pour les classes de cas. Si vous le faites, le coût du match de modèle est le coût de ce que l'extracteur fait. Un bon aperçu se trouve dans http://lamp.epfl.ch/~emir /written/MatchingObjectsWithPatterns-TR.pdf

Autres conseils

James (ci-dessus) a dit qu'il valait mieux. Cependant, si vous êtes curieux, il est toujours un bon exercice pour regarder le bytecode démontées. Vous pouvez également appeler scalac avec l'option -print, qui imprime votre programme avec toutes les fonctionnalités spécifiques Scala supprimées. Il est essentiellement Java dans les vêtements de Scala. Voici la sortie scalac -print pertinente pour l'extrait de code que vous avez donné:

def eval(e: Expr): Int = {
  <synthetic> val temp10: Expr = e;
  if (temp10.$isInstanceOf[Number]())
    temp10.$asInstanceOf[Number]().n()
  else
    if (temp10.$isInstanceOf[Sum]())
      {
        <synthetic> val temp13: Sum = temp10.$asInstanceOf[Sum]();
        Main.this.eval(temp13.e1()).+(Main.this.eval(temp13.e2()))
      }
    else
      throw new MatchError(temp10)
};

Depuis la version 2.8, Scala a eu l'annotation @switch. L'objectif est d'assurer, que la correspondance de motif sera compilé dans tableswitch ou lookupswitch au lieu de série de déclarations de if conditionnelles.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top