Llevando 3 años usando Grails casi de continuo, en mi trabajo es habitual que me pregunten cuánto tiempo le llevaría a un javero de toda la vida ponerse las pilas y coger ritmo en un proyecto en Grails. Yo siempre respondo lo mismo, Grails es un framework para hacer aplicaciones web, el javero, a veces muy a su pesar, está muy curtido en esto de probar y utilizar nuevos frameworks, de hecho encontrará Grails especialmente sencillo y fácil de utilizar, y si es de los que ha bregado a fondo con frameworks del universo (por extenso) Spring incluso te dirá que de sencillo que es no le parece un framework serio.
Pero el mayor obstáculo y la verdadera dificultad de trabajar con Grails está en el lenguaje que se utiliza: Groovy. Siendo un lenguaje, Groovy te obliga a cambiar la forma de hacer las cosas y de pensar en ellas. Afortunadamente la curva de entrada de Groovy para un javero es muy suave, no es una renuncia de Java, es casi una evolución, al principio es habitual seguir programando igual que en Java y poco a poco ir incorparando la nueva sintáxis y la nueva forma de hacer las cosas. El tiempo para una adaptación plena varia con la persona, pero típicamente lleva varias semanas o incluso meses, depende de las ganas que le ponga.
Y de todas las dificultades la mayor que se va a encontrar, y probablemente la última en superar, será entender y usar adecuadamente el concepto de
Closure
en Groovy. Personalmente (es lo que a mi me ocurrió) creo que la mayor dificultad para entenderlo es que normalmente se explica
en lenguaje convencional o natural, en Inglés o en Castellano, y dicho así no se pilla.
Un ejercicio bastante didáctico, y que espero ayude a captar el concepto Closure
más rápidamente a un javero, es intentar explicarlo en Java…
Vamos a ello, para modelar los closures vamos a utilizar dos aspectos del lenguaje Java poco usados que son: las clases anonimas y las clases internas.
De momento un Closure
se puede modelar en Java como una interfaz, con un único método execute()
que acepta un mapa de argumentos
y devuelve un resultado.
1 2 3 |
|
Una implementación del método forEach()
utilizando closures sería esta
1 2 3 4 5 6 7 8 9 10 11 |
|
Y un ejemplo de uso en Java del anterior código sería el siguiente
1 2 3 4 5 6 7 8 9 10 11 12 |
|
En java usamos clases anónimas para crear el closure, pero la sintaxis como puede observarse no es muy intuitiva. En groovy el código anterior quedaría reducido a
1 2 3 |
|
Nota: El método
eachWithIndex()
debería de llamarseeach()
a secas, ver remove eachWithIndex
Si esto fuese todo, los closures no serían complicados de entender pero la cosa se complica cuando tenemos en cuenta el
aspecto más interesante de los closures:
los closures tienen acceso a las variables del contexto donde fueron creados. Para modelar esto en Java es necesario
introducir una nueva entidad Context
.
En java existe algo parecido a los closures en el aspecto de llevar consigo el contexto donde fueron creados, que son las inner clases, y de hecho se metieron en la especificación
final de Java con esta idea y con muchas dudas (que el tiempo a confirmado fundadas) sobre su utilidad.
Vamos a modelar el contexto con un clase Context
(qué basicamente es un mapa de variables) y el closure con una clase interna (inner class)
que está vez no será una interfaz si no una clase abstracta. Los argumentos del método execute()
serán en vez de un mapa un Context
y podemos crear los argumentos usando el método createArgs()
del objeto Closure
. El objeto Context
puede tener a su vez un
contexto “padre”, pudiendo formar una cadena de contextos.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
|
Como podéis ver evidentemente la cosa se ha complidado…. veamos el método forEach()
y el ejemplo de uso que prácticamente no han cambiado.
1 2 3 4 5 6 7 8 9 10 |
|
Y el ejemplo de uso en Java
1 2 3 4 5 6 7 8 9 10 11 12 13 |
|
Puede que la sintaxis de creación de las clases anónimas dentro de clases internas cxt.new Closure()
no te sea familiar, no te preocupes no estás sólo,
yo tuve que mirarlo de nuevo para escribir el post…
En groovy el código anterior quedaría reducido a
1 2 3 4 5 |
|
Espero que el post te haya servido para entender un poco mejor que son los closures de Groovy, de manera que la próxima
vez que veas un closure (recuerda que en Groovy podemos crear uno con la sintaxis simplificada de llaves cerradas { }
),
te preguntes ¿Cuáles son sus argumentos? y ¿Cuál es su contexto? Y sobre todo aunque se parecen mucho no lo confundas con
un método. El método tiene como contexto el objecto al que pertenece, el Closure
tiene como contexto el ámbito donde fue creado.