tabla quién que interprete extension estructura ejemplos cursos codigo performance scala pattern-matching bytecode

performance - quién - tabla de codigo bytecode



¿Cómo se implementa la coincidencia de patrones en Scala en el nivel de bytecode? (3)

¿Cómo se implementa la coincidencia de patrones en Scala en el nivel de bytecode?

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

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

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

PD: Puedo leer código byte de Java, por lo que una representación de bytecode sería lo suficientemente buena para mí, pero probablemente sería mejor para los otros lectores saber cómo se vería como código Java.

PPS ¿Responde el libro Programming in Scala a esta y otras preguntas similares sobre cómo se implementa Scala? He ordenado el libro, pero aún no ha llegado.


Desde la versión 2.8, Scala ha tenido la anotación @switch . El objetivo es garantizar que la coincidencia de patrones se compile en el cambio de tabla o el conmutador de búsqueda en lugar de la serie de sentencias if condicionales.


El bajo nivel se puede explorar con un desensamblador, pero la respuesta corta es que se trata de un conjunto de si / elses 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 puedes hacer con patrones o patrones y combinaciones como "caso Foo (45, x)", pero generalmente esas son solo extensiones lógicas de lo que acabo de describir. Los patrones también pueden tener protecciones, que son restricciones adicionales en los predicados. También hay casos en que el compilador puede optimizar la coincidencia de patrones, por ejemplo, cuando hay una superposición entre casos, puede unir un poco las cosas. Los patrones avanzados y la 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 Scala.

Además de todo eso, puede escribir sus propios extractores personalizados además o en lugar de los predeterminados que Scala usa para las clases de casos. Si lo hace, entonces el costo de la coincidencia de patrón es el costo de lo que sea que haga el extractor. Se encuentra una buena descripción en http://lamp.epfl.ch/~emir/written/MatchingObjectsWithPatterns-TR.pdf


James (arriba) lo dijo mejor. Sin embargo, si tiene curiosidad, siempre es un buen ejercicio observar el bytecode desensamblado. También puede invocar scalac con la opción -print , que imprimirá su programa con todas las características específicas de Scala eliminadas. Es básicamente Java en la ropa de Scala. Aquí está la salida de scalac -print relevante para el fragmento de código que le 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) };