pattern mixin companion classes basics scala main traits

mixin - En Scala; ¿Debo usar el rasgo de la aplicación?



scala class (1)

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

(1) El código con hilos que hace referencia al objeto se bloqueará hasta que se complete la inicialización estática. Sin embargo, debido a que la ejecución completa de una aplicación de extensión de un objeto se lleva a cabo durante la inicialización estática, el código concurrente siempre tendrá un punto muerto si debe sincronizarse con el objeto que lo contiene.

Esta es una pregunta difícil. Si extiendes el rasgo de la Application , básicamente estás creando una clase Java:

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

La JVM ejecuta el inicializador de clase 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 desde su aplicación que nuevamente necesita acceder a una instancia de MyApplication , su aplicación se bloquearía debido a que la inicialización de la clase solo se completa después de que se haya ejecutado todo el programa. Esto implica una paradoja, ya que no se puede crear ninguna instancia mientras el programa se esté ejecutando.

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

Un inicializador de clase no toma ningún argumento. Además, se ejecuta primero, antes de que cualquier valor pueda ser entregado a la clase, ya que el inicializador de la clase debe ejecutarse antes de que incluso pueda asignar un valor de campo estático. Por lo tanto, los 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 pueden optimizar o JIT el código en el cuerpo de una aplicación de extensión de objeto. Esto puede conducir a una degradación significativa del rendimiento.

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 static 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 clase, que sin embargo es el código del método main su aplicación si está utilizando el rasgo de la Application .

El rasgo de la App arregla todo esto extendiendo DelayedInit . Este rasgo es conocido explícitamente por el compilador de Scala, por lo que el código de inicialización no se ejecuta desde un inicializador de clase sino desde otro método. Tenga en cuenta la referencia para el nombre que se tenía al ú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 de Scala ajusta cualquier código de inicialización de su clase u objeto de implementación en una función for name que luego se pasa al método delayedInit . Ningún 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 encuentra alrededor del punto de entrada del programa y salir. Sin embargo, hay algunas advertencias de este enfoque y el uso de DelayedInit por lo tanto, está en desuso. En realidad, solo debe confiar en el rasgo de la App que resuelve los problemas que impone el rasgo de la Application . No debes implementar DelayedInit directamente.

Aún puede definir un método main si lo desea, siempre que lo defina en un object . Esto es principalmente una cuestión de estilo:

object HelloWorld { def main(args: Array[String]) { println("Hello, world!") } }

Acabo de empezar a aprender Scala y muchos de los tutoriales que estoy siguiendo utilizan una combinación de diferentes representaciones para un método main . Aparte del método principal familiar; También está el uso de rasgos de App o Application . Parece que la Application ha quedado en desuso 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 explicarme:

  • ¿Cómo funcionan los rasgos de la App y la Application ?
  • ¿Por qué ya no se recomienda la App rasgo y qué hace que el rasgo de la App sea ​​diferente?
  • ¿Dónde debo usar el método principal tradicional y cuándo debo usar la App para iniciar mi programa? ¿Cuál es la diferencia entre los dos enfoques?