Lenguaje para scripting: Scala o Groovy?

Ultimamente que he estado descubriendo varias de las bondades de Scala, me puse a pensar si también sería una buena opción para hacer scripting. Por "scripting" me refiero simplemente a hacer programas sencillos que se ejecutan una vez en la vida, o de manera muy esporádica, o como tarea periódica no interactiva.

Hay ocasiones en que los scripts de bash no son suficientes. El ejemplo típico es cuando te piden leer un archivo de texto en cierto formato, comparar los datos con lo que tengas en una base de datos, hacer un archivo de resultados y enviarlo por correo a ciertas personas. Sobre todo si ya tienes varias partes de esta lógica implementadas en un sistema que tienes hecho en Java.

Hacer scripting en Java es extremadamente tedioso. Para empezar, estrictamente lo que se dice scripting pues no se puede hacer. Obviamente puedes hacer una clase con un main y desde ahí invocar el código que necesitas, procesar datos, etc etc pero pues hay que compilarlo y luego ejecutarlo y para eso hay que ponerle un classpath probablemente bastante largo y es una lata. Simplemente el tener que estar compilando ya te lleva a que uses alguna herramienta para llevarlo como proyecto y, sin importar que uses Gradle/Ant/Maven/Ivy, ya se complicó demasiado el asunto.

A veces te piden hacer algo que inmediatamente sabes cómo podrías hacer en Java o Groovy o algún lenguaje JVM. Cuando es algo "quick and dirty" pues hasta puedes crear el script en el equipo donde lo vas a ejecutar, o si tienes un ambiente de pruebas remoto pues mejor, pero sobre todo cuando es solamente leer datos, no vas a modificar nada, muchas veces se puede hacer directamente en el ambiente de producción (con mucho cuidado y precauciones).

En fin. Habrá un sinnúmero de situaciones en las que sea necesario, válido y conveniente hacer un script sencillo. De hecho llevo un tiempo ya usando Groovy para esto, porque se presta bastante bien para ese tipo de problemas. Primero que nada, puedes hacer un programa en Groovy y ejecutarlo sin tener que compilarlo primero (que si se compila en el momento, etc no es tan importante, la cosa que puedes hacer un archivo .groovy de 3 líneas y ejecutarlo sin pasar por una etapa explícita de compilación).

Pues bien, se me ocurrió que tal vez podría convertir algunos de estos scripts a Scala, como ejercicio de programación nada más, y de paso ver si tenían mejor desempeño, si salía más o menos código, etc. Finalmente se puede aprovechar la parte de programación funcional, habrá que convertir a tipos estáticos, pero pues todo lo de concurrencia no se va a usar.

El resultado? La conversión fue algo dolorosa. En particular, la conversión a tipado estático fue algo latosa, porque pues en Groovy hay mucho def algo=objeto.metodo1.metodo2 que es muy conveniente al momento de la codificación pero cuando estás leyendo el código hay que investigar qué devuelve objeto.metodo1 para saber qué esperar de metodo2. La desventaja del duck typing es que para interpretar código hay que hacerle al ornitólogo.

Pero eso no fue tanto problema. Finalmente después de varias iteraciones, ya no tenía errores de sintaxis o de clases no encontradas, etc. Pero ahí empezaron también varias broncas, algunas de las cuales tal vez sean derivadas de mi poco conocimiento de Scala, o tal vez sea porque simplemente no hay equivalente en este lenguaje.

Groovy tiene un mecanismo para manejo de dependencias incluso en scripts, llamado Grape, del cual ya he escrito anteriormente. Este mecanismo es muy conveniente porque te olvidas de estar manejando el classpath en muchos casos cuando utilizas bibliotecas disponibles en Maven o Ivy. Pero pues en Scala no hay algo similar, por lo que hay que manejar las dependencias a manita, o de menos echando mano de algunos trucos con ayuda de Ivy.

Otra cosa que tiene Groovy, no sé ni cómo se llame oficialmente la característica, pero la cosa es que tu script puede hacer referencia a una clase que no está en el script y entre los lugares donde la busca está el mismo directorio donde está el script y si encuentra que la clase está ahí pero como fuente de Groovy, la puede utilizar. Es decir, suponiendo que tengo un archivo Componente.groovy con esto:

@Grab('org.slf4j:slf4j-api:1.6.1')
class Componente {

  private org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(getClass())

  def hazAlgo() {
    log.info "algo"
  }
}

Y en ese mismo directorio tengo un archivo Programa.groovy con algo así:

@Grab('org.slf4j:slf4j-simple:1.6.1')
def comp = new Componente()
comp.hazAlgo()
println "Listo"

Si me meto ahí y ejecuto simplemente groovy Programa.groovy, aparecerá la línea que imprime "Listo". En cambio en Scala, si tengo un Componente.scala con esto:

class Componente {

  def hazAlgo()={
    println("algo")
  }
}

Y un Programa.scala con esto:

val comp = new Componente()
comp.hazAlgo
println("Listo")

Si tecleo scala Programa.scala me sale un error de que no encuentra la clase Componente. Para que corra, tengo que indicarle cada archivo que debe incluir antes de mi script: scala -i Componente.scala Programa.scala, pero entonces al terminar de ejecutarse el script, se queda en modo interactivo, a menos que la última línea de tu script sea sys.exit.

Al final todo esto se reduce a simple incomodidad, o inconveniencia. Es más cómodo teclear groovy Programa.groovy que tener que teclear scala -classpath ruta/a/repo/slf4j-api-1.6.1.jar:ruta/a/repo/slf4j-simple-1.6.1.jar -i Componente1.scala -i Componente2.scala Programa.scala. Pero eso se pone en un .bat o .sh y listo.

Después de todo eso, ya por fin pude ejecutar mi script. Y lo que terminó de convencerme de NO usar Scala para scripting, fue el tiempo de arranque. Algo que he notado en Scala es que el compilador es leeeeeeeeento. Normalmente no tengo broncas con eso porque si un tiempo de compilación mayor se traduce en código optimizado que resulte en tiempo de ejecución menor, es completamente aceptable. Pero si el compilador se tarda tanto para compilar un script (cosa que va a hacer cada vez que se ejecute ese script), no es tan aceptable (en todo caso habría que tener clases compiladas, pero terminamos en el mismo problema que teníamos inicialmente en Java).

En fin. Una prueba más de que hay herramientas para todo y hay que saber escoger la mejor herramienta para la tarea que hay que resolver. Y desde mi punto de vista, la mejor herramienta para hacer scripting sobre la JVM es Groovy.

Comentarios

Opciones de visualización de comentarios

Seleccione la forma que prefiera para mostrar los comentarios y haga clic en «Guardar las opciones» para activar los cambios.

Yeap. El tipeo estático

Yeap.

El tipeo estático requiere que el compilador haga algún trabajo mientras que el dinámico dice "... Fuck it, will do it live..."

Quizá para tareas que sean más grandes y complejas donde no se tenga que modificar el script tan seguido puede haber una ventaja pero ya no sería script sino .. programas de apoyo? No sé.

Lo bueno de Groovy es que ya sabes de entrada muchas cosas de él y conforme lo usas vas sabiendo más.

Para scripts también esta Python y Ruby, muy buenos para ese tipo de tareas de administración. No sé que tan bueno sería usar Jython y JRuby .. .quizá no tanto, de hecho el primer objetivo de Groovy fue precisamente ofrecer las ventajas dinámicas de Ruby pero con un "L&F" Javero.

:)

Imagen de ezamudio

Groovy

La razón inicial para usar Groovy fue el conocimiento previo de Java. Cuando te conoces bien la plataforma, poder hacer scripts en Groovy es muy rápido. He hecho scripts en Ruby también y está muy chido pero siempre me trabo un rato buscando cómo carajos abrir un archivo y leerlo línea por línea y cosas así bien básicas (conexiones a base de datos, etc).

En Groovy puedes hacer scripts que incluso carguen un application context de Spring. Como dices, terminan siendo más bien programas complementarios, cronjobs, como quieras llamarles (depende de cómo los uses).

Groovy

Se inspira en Ruby el cual es un buen lenguaje script el cual se inspira en Python el cual es otro lenguaje para script's,por lo que Groovy en caso de preferir la plataforma Java,dado que el rendimiento no es importante y no se piensa en mejorar el programa ,las ventajas de Scala son nulas.

Ruby no tanto en Python

nota al margen @BT En realidad Ruby no se inspiró (tanto) en Python, aunque son sospechosamente similares. Pero si se basó mucho más en Perl ( por ejemplo el scope de las variables definido con un caracter por ejemplo ) y en Smalltalk ( el uso de bloques de código que Python no tiene )

Imagen de Sr. Negativo

Groovy vs Scala

Groovy me parece más fácil de aprender que Scala.

Imagen de JaimeItlzc

Groovy

Me gusta mas groovy igual que Sr. Negativo, la verdad cuando de inicio empece a meterle se me hacia medio raro pero poco a poco me fui acoplando mucho, me gusta mucho la manera en la que haces los scripts y me encanto mas una haciendo la interfaz grafica.

Saludos.

Yo detesto Groovy xP

No sé, pues está chido eso del scripting porqué cómo bien dices bash no la rifa siempre para todo (aunque si para un buen de cosas). Ahora creo que estamos viendo con enfoques muy diferentes a Scala y a Groovy. Groovy (cómo han dicho) es un Ruby con un toque Javalesco; por lo que no me gusta. Es cierto que si sabes Java pues Groovy se te hará una nada.

Groovy fue pensado justamente para poder llevar a cabo labores de scripting para la gente más Javalera, mientras que JRuby o Jython son simplemente implementaciones de Ruby y Python (correspondientemente), en mi caso me decantaría más por uno de estos dos. Claro que, comparado con Groovy (que de verdad no entiendo porqué toda la gente Java está tan entusiasta con Groovy) la comunidad JRuby o Jython son todavía muy pequeñas.

Habrá que ver ventajas y desventajas de cada uno. En mi caso cómo lenguaje alternativo por mucho me quedo con Scala (conciso, limpio, algo de funcional, una sintaxis muy bien pensada -para mi-) y cómo lenguaje de scripting pues hasta la fecha uso Ruby a pie, pero de tener que usar uno de JVM me iba por JRuby o Jython (es que Python tiene una sintaxis más cool).

En el caso de Scala cómo scripting, pues de entrada Scala no es de scripting, es un lenguaje cómo dice Bruce Eckel "de tipo estático que parece dinámico". Pensado principalmente para labores de concurrencia y no de hacer un script a 3 patadas.

No considero una comparación justa, creo que sería mejor ver una comparación JRuby y Groovy o Jython y Groovy, los cuales aunque tienen ciertas diferencias comparten muchas otras características.

Imagen de ezamudio

no los uso

No uso JRuby ni Jython, por eso no los comparo. Estoy usando Scala en algunas aplicaciones precisamente para comunicación entre procesos y cosas de concurrencia, y se me ocurrió ver qué tal el scripting en Scala.

Si ves otros posts en mi blog verás que me he metido a estos dos lenguajes de igual forma, y lo que me interesa es ver para qué sirve mejor cada uno, más allá de leer otros blogs donde te dicen que uno es lo mejor que existe porque no pones punto y coma o porque tienes closures, o que otro es mejor por el tipado estático, etc.

En esta ocasión me parece que el ganador claramente es Groovy, pero no estoy diciendo que sea un mejor lenguaje que Scala. Yo honestamente no me decido si es mejor el tipado dinámico o el estático; pienso que cada uno tiene sus ventajas y desventajas. De Scala me gusta mucho la parte de Actors, la sobrecarga de operadores, el pattern matching, etc. Pero como han dicho ya varios y como me di cuenta después de estas pruebas que hice, Scala es mejor usarlo compilado.

Re: no los uso

Así es. Yo tampoco dije que tu hubieses dicho que Groovy era mejor que Scala. Pero creo que la comparación es algo "non-matching" porqué los dos lenguajes son muy diferentes (desde la sintaxis hasta la razón de ser de dicho lenguaje).

Estoy totalmente de acuerdo cuando dices que no te has decidido si tipo estático o dinámico, ya que cada uno tiene sus (des)ventajas y eso es muy cierto. Existe lo que yo considero una máxima que dice: "Zapatero a sus zapatos"; decir que X o Y tecnología es mejor no lo veo bien, lo que uno puede decir es un punto personal que no necesariamente tiene que encajar con el de los demás (aunque a veces el gusto o el entusiasmo por algo es tremendo y caemos en los dogmas xD -¿a quién no le ha pasado?-). Volviendo...con esto quiere decir que pues Groovy tiene su lugar (hacer scripts a 3 patadas sin perder todo lo que ya habías hecho en Java) y Scala tiene su parte (programación concurrente).

Obviamente en este caso (¿cuál lenguaje de entre Groovy y Scala es mejor para scripting?) iba a ganar Groovy. Cómo si nos ponemos a comparar "De entre Groovy y Scala, ¿cuál es mejor para programación funcional y concurrente?", pues gana Scala.

Imagen de ezamudio

obviedad

Es que para mí no era obvio que Groovy iba a ganar... tenía la sospecha, pero quise experimentar para comprobarlo y estar 100% seguro.

En posts anteriores he escrito algo acerca de concurrencia con Scala y pues simplemente no hay equivalente en Groovy, al menos no "out of the box"; puedes usar GPars para implementar Actors en Groovy pero no se compara, por lo del pattern matching en Scala.

Imagen de bferro

Es interesante cómo el creador de Groovy defiende Scala

Ya lo había posteado con anterioridad. En este blog (http://macstrac.blogspot.com/2009/04/scala-as-long-term-replacement-for....) que tiene dos años y sigue activo, James Strachan defiende Scala de una manera admirable. Sería bueno que los que no lo han leído lo lean. Vale la pena

Imagen de ezamudio

Luxspes

Luxspes lo menciona a cada rato. El resumen es que si el creador de Groovy hubiera sabido de la existencia de Scala, nunca hubiera creado Groovy.

Pero creo que es bueno que ambos existan, porque cada uno ha tomado distintas direcciones. Por ejemplo esto del scripting es algo que la comunidad de Groovy claramente tiene en mente y ellos mismos usan, por eso todo lo de Grape y cosas como buscar las clases aunque sean scripteadas en el mismo directorio, etc. Detrás de cada lenguaje hay una filosofía distinta.

Imagen de skuarch

Groovy

a mi me gusta groovy por que es sencillo y es una extencion de java (cuando menos yo asi lo veo) y creo que para cosas rapidas es bastante bueno

Imagen de tuxin39

Objetivo de scala

Según el libro "Programming in Scala", las aplicaciones de Scala son:

"You can apply Scala to a wide range of programming tasks, from writing small scripts to
building large systems."

pues ahora resulta que no es tan sencillo aplicar el script , a lo mejor los creadores no lo han aplicado en el ambiente productivo, posiblemente le falte madurar o replantear sus aplciaciones.

Estoy aprendiendo el lenguaje aun, no he encontrado la razón por la cual el compilador perdona los espacios, cuando invocas a un metodo de esta forma:

scala> val msg2: java.lang.String = "Hello again, world!"
msg2: java.lang.String = Hello again, world!

scala> val msg2: java.lang. String = "Hello again, world!"
msg2: java.lang.String = Hello again, world!

Notar el espacio "java.lang. String"

Saludos

Imagen de ezamudio

keyword:small

Tal vez la clave es que dicen small scripts. Para cosas MUY sencillas no hay bronca (fuera de que el tiempo de arranque es mayor). En mi caso estaba probando con un script, digamos, mediano, que tiene un par de dependencias externas y que usa una clase scripteada en un archivo separado.

Imagen de bferro

Sería bueno discutir qué es un scripting language

Sería bueno discutir que es un scripting language para entonces tener el contexto adecuado para discutir las bondades de los lenguajes de programación a la hora de hacer scripting.

@tuxin39 En realidad estás

@tuxin39 En realidad estás declarando el tipo, pero sí casi todos los compiladores modernos "perdonan" ( irónicmente más bien lo ignoran ) el espacio en blanco.

Por lo que en Scala ( o Java para poner otro ejemplo ) esto es posible:

java
.
lang
.
String

nombre
=

"El nombre"
;

O bien:

java    .   lang   .   String  nombre  =    "El nombre"
;

Que como supondrás equivale a:

java.lang.String nombre = "El nombre";

Una excepción de los que no lo ignoran es el intérprete de Python que lo usa ( el retorno de carro ) para saber donde empieza y donde termina el cuerpo de algo:

def una_funcion() :
     con_su_cuerpo()  #inicia cuerpo
     if   condicion :
         cuerpo_condicion()  # incia cuerpo del if
    siguiente() #fuera del if
    return # termina funcion
def otra_funcion():
    #empieza otra funcion
    pass

Por lo que el espacio en blanco no es ignorado en todos los casos.

Otro ejemplo era..... me parece una versión muy vieja de Fortran , pero ahí era horrible porque más bien NO requería espacios en blanco, por ejemplo:

DO I=1,N
         READ(*,*) X
         IF (X.GE.0.0) THEN
            Y=X**3
            SUM=SUM+Y
         END IF
      END DO
<code>

podría escribirse:

<code>
DO I=1,N
         READ(*,*) X
         IF (X.GE.0.0) THEN
            Y=X**3
           SUM=SUM+Y
ENDIFENDDO

O algo así era la cosa :)

Imagen de Sr. Negativo

Horoscopo Chino en Groovy

Bueno un pequeño ejemplo en Groovy

Horoscopo chino

//Signos chinos en Groovy
package ejemplo_groovy

/**
 *
 * @author Sr. Negativo
 */

class Prueba5 {
   
    static void main(String[] args){
       
    //def diccionario=["clave1":valor1,"clave2":valor2]
        def anyo_nac=["Sr N":1981,"Oscar":1982,"Enrique":1983,"Javier":1984,"Jaime":1985]
        def horos=""
        // anyo_nac.each() { key, value -> println "${key} == ${value}" };
       
        //clousure
        def calcularResto={ x, y -> return x % y }
       
        anyo_nac.each() { key, value ->
            //invocar al closure
        def llamarResto= calcularResto(value,12)
        switch(llamarResto){
                case 0:
                horos="mono"
                break
                case 1:
                horos="gallo"
                break
                case 2:
                horos="perro"
                break
                case 3:
                horos="cerdo"
                break
                case 4:
                horos="rata"
                break
                case 5:
                horos="buey"
                break
                case 6:
                horos="tigre"
                break
                case 7:
                horos="conejo"
                break
                case 8:
                horos="dragon"
                break
                case 9:
                horos="serpiente"
                break
                case 10:
                horos="caballo"
                break
                case 11:
                horos="cabra"
                break
               
               
            }//fin switch
           
           
            println "${key} nacio en ${value} le corresponde el signo  del ${horos}"
       
        };
       
       
       

       
    }//fin main
       
}//fin clase

Salida:

Sr N nacio en 1981 le corresponde el signo del gallo
Oscar nacio en 1982 le corresponde el signo del perro
Enrique nacio en 1983 le corresponde el signo del cerdo
Javier nacio en 1984 le corresponde el signo del rata

Ahora una comparación con Java

Imagen de tuxin39

Gracias

Ok, deja estudiar sobre este detalle y comprobarlo, lo que hace el ide y el autocompletar. Saludos y gracias.

Que versión de scala usaste?

Hola @ezamudio, que versión de scala usaste?

Imagen de ezamudio

2.9.0.1

Las pruebas que hice al escribir este post fueron con 2.9.0.1. Después salió la 2.9.1 que tiene un tiempo de arranque notablemente menor, aunque sigue sin alcanzar a Groovy. Pero si son script que van a hacer tareas complejas, creo que ya puede ser aceptable usar Scala (como scripting). Aunque sigo creyendo que el fuerte de Scala no es scripting.

Imagen de ezamudio

horóscopo chino

Ese horóscopo se puede optimizar bastante. Es mejor tener una lista con los animales y simplemente tomar el del índice apropiado, incluso sobra una función:

def animales=["mono", "gallo", "perro", "cerdo", "rata", "buey", "tigre", "conejo", "dragon", "serpiente", "caballo", "cabra"]
def horos=animales[value % animales.size()]

Groovy

hola que tal yo soy nuevo en el lengueje de groovy y quisiera saber como puedo hacer una suma,resta multiplicacion y division con menu

Imagen de Sr. Negativo

Re: Groovy

De la misma manera que los haces con Java

import java.util.Scanner

static int  menu(){
        int  opc=0
        Scanner t=new Scanner(System.in)
        println "\tMenu"
        println "1. Suma"
        println "2. Resta"
        println "3. Producto"
        println "4. Division"
        println "5. Salir"
while(opc<=0 || opc>5){
                println"Tu opcion: "
                opc=t.nextInt()
}              
       
        return opc
}

static void main(String ... args) {
       
        Scanner entrada=new Scanner(System.in)
        def num1=0
        def num2=0

       

        for(;;){
                println "Introduce un numero:"
                num1=entrada.nextInt()
            println "Introdce otro numero:"
            num2=entrada.nextInt()
            int opc=menu()

        switch(opc) {
                case 1:
                println "suma"
                println "la suma de $num1 y $num2 es: "+ (num1+num2)
                break;
                case 2:
                println "resta"
                println "la resta de $num1 y $num2 es: "+ (num1-num2)
                break;
                case 3:
                println "producto"
                println "el producto de $num1 y $num2 es: "+ (num1*num2)
                break;
                case 4:
                println "Division"
                println "la division de $num1 y $num2 es: "+ (num1/num2)
                break;
                case 5:
                System.exit(0)
                break;
                default:
                println "opcion invalida"
                break;
        }

}

}

Servido joven.

Gracias Sr. Negativo

osea que de la misma manera que se hace en java, groovy puede leer codigo de java

Imagen de Sr. Negativo

Código java en groovy

Así es. Puedes seguir usando (en algunos casos) la sintaxis de java en los programas groovy.