Cómo recargar una clase o paquete en Scala REPL?


Casi siempre tengo una sesión de REPL de Scala o dos abiertas, lo que hace que sea muy fácil dar clases Java o Scala una prueba rápida. Pero si cambio una clase y la recompilo, el REPL continúa con el antiguo cargado. ¿Hay alguna manera de hacer que vuelva a cargar la clase, en lugar de tener que reiniciar el REPL?

Solo para dar un ejemplo concreto, supongamos que tenemos el archivo Test.scala:

object Test { def hello = "Hello World" }

Lo compilamos e iniciamos el REPL:

~/pkg/scala-2.8.0.Beta1-prerelease$ bin/scala
Welcome to Scala version 2.8.0.Beta1-prerelease
(Java HotSpot(TM) Server VM, Java 1.6.0_16).
Type in expressions to have them evaluated.
Type :help for more information.

scala> Test.hello
res0: java.lang.String = Hello World

Luego cambiamos el archivo fuente a

object Test {
  def hello = "Hello World"
  def goodbye = "Goodbye, Cruel World"
}

Pero no podemos usarlo:

scala> Test.goodbye
<console>:5: error: value goodbye is not a member of object Test
       Test.goodbye
            ^

scala> import Test;
<console>:1: error: '.' expected but ';' found.
       import Test;
Author: Jacek Laskowski, 2010-03-18

5 answers

La recarga de clases no es un problema fácil. De hecho, es algo que la JVM hace muy difícil. Usted tiene un par de opciones sin embargo:

  • Inicie el REPL de Scala en modo de depuración. El depurador JVM tiene alguna recarga incorporada que funciona a nivel de método. No le ayudará con el caso que dio, pero manejaría algo simple como cambiar la implementación de un método.
  • Use JRebel ( http://www.zeroturnaround.com/jrebel ). JRebel es básicamente un solución de recarga de clase súper cargada para JVM. Puede manejar adición/eliminación de miembros, clases nuevas / eliminadas, cambios de definición, etc. Casi lo único que no puede manejar son los cambios en la jerarquía de clases (agregando una super-interfaz, para ejemplo). No es una herramienta gratuita, pero ofrecen una licencia complementaria que se limita a las unidades de compilación de Scala.

Desafortunadamente, ambos están limitados por los detalles de implementación de la REPL de Scala. Yo uso JRebel, y por lo general hace el truco, pero todavía hay casos en los que el REPL no reflejará la(s) clase (s) recargada (s). Aún así, es mejor que nada.

 27
Author: Daniel Spiewak,
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
2010-03-18 18:57:24

Existe una alternativa a recargar la clase si el objetivo es no tener que repetir comandos anteriores. El REPL tiene el comando

:replay

Que reinicia el entorno REPL y reproduce todos los comandos válidos anteriores. (Los inválidos se omiten, por lo que si estaba mal antes, no funcionará de repente.) Cuando se restablece el REPL, se recargan las clases, por lo que los nuevos comandos pueden utilizar el contenido de las clases recompiladas (de hecho, los comandos antiguos también utilizarán los recompilados clase).

Esta no es una solución general, pero es un atajo útil para extender una sesión individual con estado re-computable.

Nota: esto se aplica al REPL Scala desnudo. Si lo ejecuta desde SBT o algún otro entorno, puede o no funcionar dependiendo de cómo SBT o el otro entorno empaqueta las clases up si no actualiza lo que está en el classpath real que se está utilizando, ¡por supuesto que no funcionará!

 38
Author: Rex Kerr,
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
2015-06-03 18:01:25

Hay un comando cumplir con el requisito

:load path/to/file.scala

Que recargará el archivo fuente de scala y lo recompilará a clases, luego puede reproducir su código

 7
Author: jiahut,
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-09-26 07:53:03

Esto funciona para mí....

Si su nuevo archivo fuente Test.scala se ve algo como esto...

package com.tests

object Test {
  def hello = "Hello World"
  def goodbye = "Goodbye, Cruel World"
}

Primero tiene que cargar los nuevos cambios en Scala console (REPL).

:load src/main/scala/com/tests/examples/Test.scala

Luego vuelva a importar el paquete para que pueda hacer referencia al nuevo código en la consola de Scala.

import com.tests.Test

Ahora disfruta de tu nuevo código sin reiniciar tu sesión:)

scala> Test.goodbye
res0: String = Goodbye, Cruel World
 6
Author: cevaris,
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-09-26 20:37:03

Si el .scala archivo está en el directorio donde se inicia el REPL puede ommit la ruta completa, simplemente poner :load myfile.scala, y luego importar.

 1
Author: Ignacio,
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
2015-10-07 20:15:15