Pregunta

¿Cómo es la coincidencia de patrones en Scala implementa a nivel de código de bytes?

¿Es como una serie de construcciones if (x instanceof Foo), o algo más? ¿Cuáles son sus implicaciones en el rendimiento?

Por ejemplo, dado el siguiente código (de Scala Por Ejemplo páginas 46-48), ¿cómo el código equivalente Java para el método eval parece?

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. Puedo leer el código de bytes de Java, por lo que una representación de código de bytes sería lo suficientemente bueno para mí, pero probablemente sería mejor para los demás lectores saber cómo se vería como código Java.

P.P.S. ¿El libro en Scala dar una respuesta a esta y otras cuestiones similares acerca de cómo Scala ¿está implementado? He ordenado el libro, pero todavía no ha llegado.

¿Fue útil?

Solución

El bajo nivel puede ser explorada con un desensamblador, pero la respuesta corta es que es un montón de si / vigilara donde el predicado depende del patrón

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

Hay mucho más que se puede hacer con patrones similares o patrones y combinaciones como "caso Foo (45, x)", pero en general esos son sólo extensiones lógicas de lo que acabo de describir. Los patrones también pueden tener guardias, que son limitaciones adicionales a los predicados. También hay casos en los que el compilador puede optimizar la coincidencia de patrones, por ejemplo cuando hay cierta superposición entre casos podría confluir las cosas un poco. patrones avanzados y optimización son un área activa de trabajo en el compilador, por lo que no se sorprenda si el código de bytes mejora sustancialmente sobre estas reglas básicas en las versiones actuales y futuras de la Scala.

Además de todo eso, usted puede escribir sus propios extractores personalizados, además o en lugar de la falta de pago Scala utiliza para las clases de casos. Si lo hace, entonces el costo del ajuste de patrones es el costo de lo que sea el extractor hace. Un buen resumen se encuentra en http://lamp.epfl.ch/~emir /written/MatchingObjectsWithPatterns-TR.pdf

Otros consejos

James (arriba) lo dijo mejor. Sin embargo, si usted es curioso que siempre es un buen ejercicio para mirar el código de bytes desmontado. También puede invocar scalac con la opción -print, que imprimirá su programa con todas las características específicas de Scala retirados. Se trata básicamente de Java con piel de Scala. Aquí está la salida scalac -print relevante para el fragmento de código que diste:

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

Desde la versión 2.8, Scala ha tenido la @switch anotación. El objetivo es asegurar que la coincidencia de patrones se compila en tableswitch o lookupswitch lugar de una combinación de enunciados condicionales if.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top