Que significa REPL para Java

Tal vez sea un desarrollador de Clojure o Scala en el armario, o tal vez haya trabajado con LISP en el pasado. Si es así, es muy probable que haya utilizado un REPL como parte de su rutina diaria. REPL , o read-eval-print-loop, es una interfaz de shell que lee cada línea de entrada, evalúa esa línea y luego imprime el resultado. Comentarios instantáneos, ¡bueno!

Cuando usa un REPL, está escribiendo código de forma interactiva y ejecutándolo sin demora. El lanzamiento de Java 9 en 2016 ofrecerá un entorno REPL completamente funcional llamado JShell (cuyo nombre en código es Kulla). Este artículo proporciona una descripción general de Java REPL y analiza algunas posibilidades de cómo puede usarlo en su programación Java, ¡sí, usted!

Espera, ¿Java aún no tiene un REPL?

¡Seguramente un lenguaje establecido como Java debe tener un REPL! Bueno, en realidad, no todos los lenguajes los tienen y Java es uno de los que le ha faltado. Podría decirse que, con más ceremonia y repetición que la mayoría de los lenguajes, Java es uno de los lenguajes cuyos desarrolladores más lo han merecido. Java ha tenido algo parecido a REPL durante un tiempo en forma de Java BeanShell, pero este proyecto nunca fue un REPL con todas las funciones a la par con los de otros lenguajes. Era solo un subconjunto de la sintaxis completa del lenguaje Java.

REPL reduce el tiempo de entrega

Acortar el tiempo de respuesta y los ciclos de retroalimentación tanto como sea posible es increíblemente importante para la cordura de un desarrollador. Un REPL es una gran herramienta para los desarrolladores que desean lograr precisamente eso. Los desarrolladores son más productivos cuando pueden ver los resultados de su trabajo de inmediato. Con un REPL de Java, los desarrolladores podrán escribir código, ejecutar ese código y luego continuar evolucionando su código sobre la marcha sin tener que salir para ejecutar una compilación, etc. Si bien muchos de los sistemas que usan Java están más allá de la complejidad de lo que podría ser manejado por un REPL interactivo, la mera presencia de un REPL en el JDK significa que alguien, en algún lugar, encontrará un caso de uso asombroso en poco tiempo. El hecho de que JShell exponga una API básicamente garantiza que los desarrolladores de IDE integrarán este REPL en las herramientas que usamos para escribir código.¡Solo espere hasta que Java REPL sea parte de cada IDE!

Empiece a utilizar JShell

Es importante darse cuenta de que el uso del REPL en desarrollo, Proyecto Kulla, no es para los débiles de corazón. Kulla, también conocido como JShell, no forma parte del paquete de vista previa de JDK 9 en el momento de escribir este artículo, por lo que tendrá que clonar un proyecto Mercurial, compilar el JDK y compilar JShell usted mismo. Reserve una hora para este proceso, especialmente si normalmente no está utilizando el código fuente de JDK. Tendrá que deshabilitar las advertencias como errores, y si está construyendo en OSX, asegúrese de haber instalado XCode junto con XQuartz para la biblioteca freetype. Siga las instrucciones a continuación para instalar y ejecutar Project Kulla en su entorno de desarrollo Java.

1. Instale Java 9

Para ejecutar JShell, deberá descargar e instalar la última versión de vista previa de acceso temprano para Java 9. Una vez que haya descargado Java 9, configure su JAVA_HOMEvariable de entorno y ejecute java –versionpara verificar su instalación. Esto puede ser complicado, especialmente en OSX, por lo que vale la pena comprobarlo dos veces.

2. Instale Mercurial y Project Kulla

Project Kulla es un proyecto OpenJDK, por lo que tendrás que clonar el repositorio de Mercurial para compilarlo.

A continuación, clonarás el repositorio de Kulla:

 hg clone //hg.openjdk.java.net/kulla/dev kulla 

Luego configurará la compilación:

 cd kulla bash ./configure --disable-warnings-as-errors make images 

3. Compile y ejecute REPL

Aquí está el código para compilar REPL:

 cd langtools/repl; bash ./scripts/compile.sh 

Y aquí está el código para ejecutarlo:

 bash ./scripts/run.sh 

Como señalé, la función REPL de Java aún no está lista para el consumo general, ¡pero aún podemos probarla!

Tu haces las matematicas

Para un ejemplo inicial de lo que puede hacer JShell, evaluemos algunas expresiones simples usando java.lang.Math:

Listado 1. Evaluación de expresiones matemáticas con REPL

 $ bash ./scripts/run.sh | Welcome to JShell -- Version 0.710 | Type /help for help -> Math.sqrt( 144.0f ); | Expression value is: 12.0 | assigned to temporary variable $1 of type double -> $1 + 100; | Expression value is: 112.0 | assigned to temporary variable $2 of type double -> /vars | double $1 = 12.0 | double $2 = 112.0 -> double val = Math.sqrt( 9000 ); | Added variable val of type double with initial value 94.86832980505137 

Aquí estamos evaluando expresiones, encontrando la raíz cuadrada de un número y luego sumando dos números. Este no es el código más complejo, pero debe tener en cuenta que el /varscomando nos da la capacidad de enumerar las variables creadas en la sesión de JShell. Podemos referirnos a valores de expresiones no asignadas usando una notación de signo de dólar ($). Por último, podemos crear una nueva variable y asignarle un valor.

Definir un método

Ahora se vuelve más interesante. En este ejemplo definimos un método para calcular la secuencia de Fibonacci. Una vez definido el método, verificamos qué métodos se definen con el /methodscomando. Finalmente, ejecutamos un fragmento de código para recorrer una matriz e imprimir los primeros números de la secuencia.

Listado 2. Calcule la secuencia de Fibonacci

 $ bash ./scripts/run.sh | Welcome to JShell -- Version 0.710 | Type /help for help -> long fibonacci(long number)  >> if ((number == 0)  | Added method fibonacci(long) -> /methods | fibonacci (long)long -> fibonacci( 12 ) | Expression value is: 144 | assigned to temporary variable $1 of type long -> int[] array = { 1,2,3,4,5,6,7,8 }; | Added variable array of type int[] with initial value [[email protected] -> for( long i : array ) { System.out.println(fibonacci( i )); } 1 1 2 3 5 8 13 21 

En la misma sesión de JShell puedo redefinir la definición del método Fibonacci y ejecutar el mismo código. De esta manera, puede usar REPL para ejecutar, modificar y probar rápidamente nuevos algoritmos.

Listado 3. REPL para reutilización

 -> long fibonacci(long number) { >> return 1; >> } | Modified method fibonacci(long) -> for( long i : array ) { System.out.println(fibonacci( i )); } 1 1 1 1 1 1 1 

Definir una clase

The following example demonstrates how to define an entire class in JShell and then reference that class in an expression -- all without leaving the REPL. The ability to dynamically create and test code frees you up to quickly experiment and iterate with new code.

Listing 4. Dynamic class definition

 MacOSX:repl tobrien$ bash ./scripts/run.sh | Welcome to JShell -- Version 0.710 | Type /help for help -> class Person { >> public String name; >> public int age; >> public String description; >> >> public Person( String name, int age, String description ) { >> this.name = name; >> this.age = age; >> this.description = description; >> } >> >> public String toString() { >> return this.name; >> } >> } | Added class Person -> Person p1 = new Person( "Tom", 4, "Likes Spiderman" ); | Added variable p1 of type Person with initial value Tom -> /vars | Person p1 = Tom 

While the ability to define classes dynamically is powerful it isn't like developers are clamoring to write large, multi-line definitions in an interactive shell. This is where the concept of history and being about to load and save the state of the REPL starts to become important. With the /history command you can list all of the statements and expressions evaluated in a REPL.

Listing 5. Know your /history

 -> /history class Person { public String name; public int age; public String description; public Person( String name, int age, String description ) { this.name = name; this.age = age; this.description = description; } public String toString() { return this.name; } } Person p1 = new Person( "Tom", 4, "Likes Spiderman" ); Person p2 = new Person( "Zach", 10, "Good at Math" ); /vars p1 p2 /history 

You can then save your REPL history to a file and name it so that it can be loaded again later. Here's an example:

 -> /save output.repl -> /reset | Resetting state. -> /vars -> /open output.repl -> /vars | Person p1 = Tom | Person p2 = Zach 

The /save command saves the REPL history to a file, the /reset command resets the state of the REPL, and the /open command reads in a file and executes states against the REPL. The save and open features enable you to set up very complex REPL scripts that you can use to configure different REPL scenarios.

Editing class definition on the fly

JShell also makes it possible to set a startup definition file and load definitions automatically. You can jump around your REPL history and edit named source entries. For example, if I wanted to modify the definition of the Person class from this example I could use the /list and /edit commands.

Listing 6. Modifying Person

 -> /l 1 : class Person { public String name; public int age; public String description; public Person( String name, int age, String description ) { this.name = name; this.age = age; this.description = description; } public String toString() { return this.name; } } 2 : Person p1 = new Person( "Tom", 4, "Likes Spiderman" ); 3 : Person p2 = new Person( "Zach", 10, "Good at Math" ); 4 : p1 5 : p2 -> /edit 1 

Running this /edit command loads a simple editor where I can alter the class definition and have the class updated immediately.

What's the big deal?

Talk to a Clojure or LISP programmer about how they develop day to day, and you'll see that they code within a REPL. They don't write scripts and then execute them as much as they spend most of their development time changing code interactively. If you have a few hours to spare, ask a Scala or Clojure developer about their REPL. It's how they work.

Java's a different language from Scala or Clojure. Java developers are not spending days focused on single lines of LISP that might contain entire program structures in a few statements. Most Java programs require setup to function properly, and while recent changes to the language have reduced the line count of systems written in Java we're still measuring the complexity of our systems in thousands of lines of code. The simple Person example listed above isn't useful code, and most useful code in Java carries with it a complexity that's going to be difficult to fit into a REPL-based programming environment.

Scala and Clojure developers practice something that Clojure Programming author Chas Emerick calls "iterative development" that doesn't depend on a file-based workflow. Java developers depend on tens of libraries, complex dependency hierarchies, and containers like Tomcat or TomEE. For this reason I don't predict that REPL-oriented programming will overtake traditional Java development in an IDE. Instead I see the Java REPL providing a few distinct benefits and opportunities.

1. Learning Java: Because Java programs require so much setup it can be challenging for developers learning the language to understand the syntax quickly. Java 9's REPL will become the primary way that new developers come to grips with the basic syntax.

2. Experimenting with new libraries: Java has hundreds of useful open source libraries for everything from date and time manipulation to math libraries. Without a REPL, whenever a developer wants to understand a new library they inevitably create a few throwaway classes with the usual "public static void main" ceremony. With a REPL you can just fire it up and play without this overhead.

3. Rapid prototyping: This is closer to how most Clojure and Scala developers work iteratively, but if you are working on a focused problem, a REPL makes it easy to iterate quickly on changes to classes and algorithms. With a REPL you won't have to wait for a build to finish; you can tweak the definition of a class quickly, reset your REPL, and try it again.

4. Integration with build systems: Gradle provides an interactive "shell" mode, and the Maven community have shipped similar tools in the past. Developers looking to reduce build complexity could explore using a REPL as a tool to orchestrate other systems.

My final 2c

Veo el REPL de Java como algo que comenzará a afectar el desarrollo diario en los próximos años, para aquellos que actualicen a Java 9. También creo que la comunidad de Java necesitará tiempo para adaptarse completamente a la nuevo estilo de desarrollo y comprender tanto los desafíos como las oportunidades que brinda un REPL. No espero que la mayoría de los desarrolladores de Java hagan la transición al desarrollo orientado a REPL como lo han hecho sus primos de programación Clojure, pero sí creo que veremos que REPL influye en la forma en que los nuevos desarrolladores aprenden Java. A medida que los nuevos desarrolladores de Java encuentren Java por primera vez dentro de un REPL, no hay duda de que comenzará a influir en la forma en que construimos y prototipamos sistemas basados ​​en Java.

Esta historia, "Qué significa REPL para Java" fue publicada originalmente por JavaWorld.