En Scala; ¿debo usar el rasgo de la aplicación?


Acabo de empezar a aprender Scala y muchos de los tutoriales que estoy siguiendo están utilizando una combinación de diferentes representaciones para un método main. Aparte del conocido método principal, también está el uso de traits App o Application. Parece que Application ha sido obsoleto y no se recomienda, pero no puedo encontrar ninguna información que explique mucho más allá de esto sobre cada una de estas formas de definir un punto de entrada.

Entonces, me pregunto si alguien podría explicar a me:

  • ¿Cómo funcionan los rasgos App y Application?
  • ¿Por qué el rasgo Application ya no se recomienda y qué hace el rasgo App que es diferente?
  • ¿Dónde debo usar el método principal tradicional y cuándo debo usar App para iniciar mi programa? ¿Cuál es la diferencia entre los dos enfoques?
Author: Micheal Hill, 2014-06-26

1 answers

El problema con el Application el rasgo se describe en realidad en su documentación:

(1) El código enhebrado que hace referencia al objeto se bloqueará hasta que se complete la inicialización estática. Sin embargo, debido a que toda la ejecución de una aplicación de extensión de objeto tiene lugar durante la inicialización estática, el código concurrente siempre se bloqueará si debe sincronizarse con el objeto que lo encierra.

Esto es complicado. Si extiendes el rasgo Application, estás básicamente creando una clase Java:

class MyApplication implements Application {
  static {
    // All code goes in here
  }
}

La JVM ejecuta el inicializador de clases anterior sincronizado implícitamente en la clase MyApplication. De esta manera, se asegura que no se crea ninguna instancia de MyApplication antes de que se inicialice su clase. Si genera un subproceso de su aplicación que nuevamente necesita acceder a una instancia de MyApplication, su aplicación se bloqueará ya que la inicialización de la clase solo se completa después de que todo el programa se haya ejecutado. Esto implica una paradoja ya que ninguna instancia puede ser creada como mientras tu programa esté en ejecución.

(2) Como se describió anteriormente, no hay forma de obtener los argumentos de la línea de comandos porque todo el código en el cuerpo de una Aplicación de extensión de objeto se ejecuta como parte de la inicialización estática que ocurre antes de que el método principal de la Aplicación comience la ejecución.

Un inicializador de clases no toma ningún argumento. Además, se ejecuta primero, antes de que se puedan entregar valores a la clase, ya que el inicializador de clases debe ejecutarse antes incluso podría asignar un valor de campo estático. Por lo tanto, el args que normalmente recibe en un método main se pierden.

(3) Los inicializadores estáticos se ejecutan solo una vez durante la ejecución del programa, y los autores de JVM generalmente asumen que su ejecución es relativamente corta. Por lo tanto, ciertas configuraciones de JVM pueden confundirse, o simplemente no optimizar o JIT el código en el cuerpo de una aplicación de extensión de objeto. Esto puede conducir a un rendimiento significativo degradación.

La JVM optimiza el código que se ejecuta con frecuencia. De esta manera, se asegura de que no se pierda tiempo de ejecución en métodos que no son realmente un cuello de botella de rendimiento. Sin embargo, asume con seguridad que los métodos static solo se ejecutan una vez, ya que no se pueden invocar manualmente. Por lo tanto, no optimizará el código que se ejecuta desde un inicializador de clases que, sin embargo, es el código de método main de su aplicación si está utilizando el rasgo Application.

El App rasgo soluciona todo esto extendiendo DelayedInit. Este rasgo es explícitamente conocido por el compilador de Scala, de modo que el código de inicialización no se ejecuta desde un inicializador de clases, sino desde otro método. Tenga en cuenta la para la referencia name que está relacionada con el único método del rasgo:

trait Helper extends DelayedInit {
  def delayedInit(body: => Unit) = {
    println("dummy text, printed before initialization of C")
    body
  }
}

Al implementar DelayedInit, el compilador Scala envuelve cualquier código de inicialización de su clase u objeto implementador en una función para name que luego se pasa al método delayedInit. No el código de inicialización se ejecuta directamente. De esta manera, también puede ejecutar código antes de que se ejecute un inicializador, lo que permite a Scala, por ejemplo, imprimir las métricas de tiempo de ejecución de una aplicación en la consola que se envuelve alrededor del punto de entrada y salida del programa. Sin embargo, hay algunas advertencias de este enfoque y usar DelayedInit por lo tanto está en desuso. Realmente solo debes confiar en el rasgo App que resuelve los problemas que impone el rasgo Application. No debe implementar DelayedInit directamente.

Todavía puede definir un método main si lo desea, siempre y cuando lo defina en un object. Esto es sobre todo una cuestión de estilo:

object HelloWorld {
  def main(args: Array[String]) {
    println("Hello, world!")
  }
}
 24
Author: Rafael Winterhalter,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-06-26 18:38:49