miércoles, 9 de enero de 2013

EXPLORANDO GROOVY, PARTE II

Para el programador proveniente de Java, que en la actualidad debe ser un porcentaje muy alto de los nuevos programadores de Groovy, hay ciertas cosas que saltan a la vista y generan preguntas interesantes sobre cómo se trasladan muchos de los conceptos de Java a Groovy.  Primero hay que tener en cuenta que si bien Groovy está pensado para ser fácil de aprender para los programadores da Java, es un lenguaje distinto con filosofía distinta; al mismo tiempo que es mucho mas orientado a objetos que Java, incorpora programación funcional  por medio del uso intensivo de closures y abrasa conceptos de metaprogramming y domain specific languages, lo cual lo hace un lenguaje ideal para el desarrollo de herramientas y aplicaciones de dominios complejos.

En esta entrega quiero tratar de explicar un poco mejor como resuelve el Groovy los ámbitos de las variables y como se diferencia de Java. Esta área del Groovy ha sufrido varios cambios importantes desde sus primeras versiones, así que para todos los ejemplos que voy a mostrar a continuación asumo que estamos empleando Groovy 1.8.

En el artículo anterior omití hablar de algunas variables automáticas que crea Groovy en distintos contextos, en la misma manera que Java genera this y super, Groovy ademas de estas tiene it y owner entre otros. El it lo vimos en el pasado y es el argumento de un closure en el caso que este solo tenga uno. El owner por otra parte representa el contexto donde se ejecuta el closure, que para el caso de los closures no anidados en el objeto mismo, pero para los anidados es el closure padre. Otra cosa de la que olvidé hablar es cómo los string de groovy soportan tanto comillas sencillas como dobles para sus literales, y cuando usan comillas dobles podemos usar expresiones tipo EL para la inclusión de valores

Bueno a continuación un ejemplo en el que trato de explorar un poco estos conceptos.

// scopeTests.groovy
package tests
//
class Klass {
  Closure createClosure() {
    return {
      def list = [it, owner, this]
      // creamos un closure anidado que es el que retornamos
      def nested = { list + [it, owner, this]}  
      return nested
    }
  }
}
klass = new Klass()
closure = klass.createClosure()  // creamos un closure
nested = closure(this)           // iniciamos el closure anidado 
list1 = nested('arg')            // ejecutamos el closure anidado 
list2 = closure(this)('arg')     // list1 y list2 son equivalentes
println "list1 == list2 : ${list1 == list2} : $list1"
// note como 'it' dentro del contexto del closure externo tiene el valor 
// del argumento de dicho closure, que en este caso es 'this' desde el ámbito 
// del scrip. Y ya que groovy genera un objeto que representa al archivo, es 
// decir que el archivo es una definición de clase si esta no es explícita 
println "list1[0].class.name == this.class.name : " +
        "${list1[0].class.name == this.class.name} : ${list1[0].class.name}"
// 'it' dentro del contexto del closure anidado tiene el valor 
// del argumento de dicho closure 'arg'
println "list1[3] == 'arg' : ${list1[3] == 'arg'} : ${list1[3]}"
// en el contexto del closure externo 'owner' es igual a 'this'
println "list1[1].class.name == list1[2].class.name : " +
        "${list1[1].class.name == list1[2].class.name} : ${list1[2].class.name}"  
// 'this' simpre se refiere al objeto padre sin importar que estemos en un 
// closure anidado  
println "list1[2].class.name == list1[5].class.name : " +
  "${list1[2].class.name == list1[5].class.name} : ${list1[5].class.name}"
// sin embargo 'owner' es diferente dependiendo del closure desde donde estemos 
// y su nivel de anidamiento
println "list1[1].class.name != list1[4].class.name : " +
  "${list1[1].class.name != list1[4].class.name} + : " +
  "${list1[1].class.name} : ${list1[4].class.name}"

martes, 8 de enero de 2013

Explorando Groovy, Parte I

Tenía tiempo que no sentía emoción por aprender un lenguaje de programación nuevo, y conste que tengo la costumbre de asomarme a lenguajes de programación nuevos cada cierto tiempo, pero como los lenguajes que domino bien (c, c++ y java) junto a los que conozco lo suficiente como para desarrollar en serio con ellos (bash, c#, javascript y php) cubren en general mis necesidades profesionales, no me he quedado vinculado a ninguno nuevo producto de mis múltiples exploraciones: perl, python, ruby, sather, ocalm, lisp, prolog, basic, pascal, D, y pare de contar.

Pero en estos días en un violento ataque de amor/odio sadomasoquista típico de mi relación con java decidí explorar que otras alternativas existen para desarrollar sobre la JVM, de todos los lenguajes diferentes a java que están proliferando en ese entorno dos aparentan tener un crecimiento realmente importante desde el punto de vista de las comunidades que alrededor de ellos se están formando: Scala y Groovy. Y luego de invertir unas 4 horas con estos dos muchachos el Groovy hizo click en mi cerebro y por lo tanto decidí profundizar mi entendimiento de este señor.

No voy a ponerme a describir el lenguaje, ni su historia, para eso esta wikipedia y otras muchas fuentes que hablan del groovy, lo que si voy es a ir describiendo en varios artículos algunas de las cosas que me han hecho tan atractivo el lenguaje, creo que lo mas importante para mi es que groovy me hace sentir el poder de programar en un lenguaje rico y expresivo como python o ruby, pero con una sintaxis mucho mas familiar y cómoda (para mi cerebro de c++)

Ya pasando a tema mas concreto y mostrar algunas de las cosas de groovy les dejo el siguiente código que hice para probar algunos conceptos sobre listas, mapas y closures:




// ClosuresTest1.groovy
/* Esta clase la vamos a emplear para validar datos con respecto a un valor
 * limite máximo con el cual la iniciamos en su construcción.
 */
class MaxLimit { 
    int limit 
    MaxLimit(int limit) {
        this.limit = limit
    } 
    boolean validate(String value) {  
        value.length() <= limit
    } 
    boolean validate(int value) {
        value <= limit
    } 
    String message(String value) {
        "String  limit $limit, length ${value.length()}, value $value"
    } 
    String message(int value) {
        "int limit $limit, value $value"
    }
}
// creamos una lista con tres objetos de MaxLimit con limites 4, 5 y 5
def limits = [ new MaxLimit(4), new MaxLimit(6), new MaxLimit(5) ]

/* creamos una lista de closures, aquí se puede ver ya algunas de las 
 * idiosincrasias de groovy:
 * 1.- con .each recorremos la lista 'limits' donde la variable automática 'it' 
 *     toma el valor de cada objeto iterado
 * 2.- con .add agregamos elementos a la lista 'closures'
 * 3.- lo que agregamos a la lista 'closures' son mapas con dos llaves: 
 *     validate y message cada una apuntando por referencia a los métodos del 
 *     mismo nombre del objeto 'it' iterado. Aquí mostramos lo poderoso que es
 *     la capacidad de manejo de multimetodos donde podemos apuntar con un solo 
 *     closure a varios métodos con el mismo nombre pero con diferentes  
 *     argumentos, definitivamente muy poderoso y elegante.
 */
def closures = []
limits.each { closures.add([validate: it.&validate, message: it.&message]) }

def data = [6, 'long string', 'medium', 'short', 'tiny', 5, 4]

/* Aquí recorremos una lista heterogénea de datos 'data' e internamente  
 * recorremos y aplicamos la lista 'closures' a cada 'datum', imprimiendo
 * el mensaje del objeto MaxLimit en caso que validate sea verdadero.
 * Imaginen toda la basura sintactica que llevaria hacer lo mismo con java.
 */
data.each { datum ->
    closures.each { closure -> 
     if (closure.validate(datum)) println closure.message(datum) 
    } 
}