Las closures son algo así como funciones de primer orden.
En python se pueden construir con lambda-construcciones:
Código:
my_fun = lambda x: 2 * x
assert(my_fun(4) == 8)
En Javascript,
Código:
my_fun = function(x) { return 2 * x; }
alert(my_fun(8) == 4); // True!
Pero esto no es una closure.
Esto es simplemente una función de primer orden, igual que la que tú has puesto.
Una closure es algo más potente.
Es una función de primer orden cuyas variables internas son de otro ámbito (scope) a este en el que se referencia.
Por ejemplo,
crea_funcion_mayor_que(x) nos devuelve una *función* de un parámetro y que al evaluarla sobre él nos dice cierto si y es mayor que un cierto x.
Programada, por ejemplo, en Python, sería algo tal que así:
Código:
def crea_funcion_mayor_que (x):
def my_f (y):
return y > x
return my_f;
## Esto podría expresarse también como
def crea_funcion_mayor_que (x):
return lambda y: y > x
mayor_a5 = crea_funcion_mayor_que(5)
assert(mayor_a5(6) == True)
Como ves, no es algo exclusivo de Groovy.
Es algo ampliamente usado en programación funcional, muy útil, y produce código que puede ser bastante entendible (dentro de lo que es entendible en programación funcional, que es algo con lo que alguna gente, desde el punto de vista imperativo no está al principio tan de acuerdo).
No obstante, dese mi punto de vista, Groovy como intento de programación dinámica, al correr bajo la JVM tiene ciertos problemas de diseño inherentes a la JVM.
Si no necesitas el API de Java o interactuar con programas más viejos realizados para esta misma máquina virtual, mi consejo es utilizar un lenguaje que, en aras de soportar correctamente el paradigma funcional,
tenga soporte para la optimización de la recursión terminal.
Es un bug que lleva años abierto en la JVM y que no parece que vaya a ser implementado a corto plazo.
Es decir, que una función recursiva en tu programa podrá terminar con una StackOverflowException simplemente por la implementación de la JVM.
Si quieres un ejemplo de esto, busca por una implementación recursiva y eficiente de fibonacci (esta solución se basa en la matriz ((1, 0), (0, 1)) de generación de la sucesión, elevándola a la iteración deseada se obtiene la salida que se pretende).
Ahora estoy un poquito dormido para programarla aquí ^ ^
Oh, y también porque Groovy hace "heavy-use" de la java.lang.Reflection y ese tipo de artilugios para determinar en tiempo de ejecución cosas que deberían de inferirse en tiempo de compilación o bien no requerirse explícitamente mediante técnicas de boxing de valores a un nivel más bajo.
Si necesitas interactuar con el API de Java o con tus clases ya hechas compatibles con la JVM entonces me callo : )
Se me olvidaba: hay lenguajes que no soportan closures.
Por ejemplo, C.
En C lo más parecido que puedes tener es copiar el código en ensamblador de una función: dado (int(*ptrFun)(int, int)), hallar *funBodyEnd por aritmética de punteros, colocando un marcador en el código, por ejemplo compilando el código con GCC con atributos que ahora no recuerdo, pero son anotaciones del tipo __attribute__(algo) al final del código de la función), y luego hacer algo como
typedef int(*)(int, int) myFun;
myFun* fclosure = (myFun*) malloc(funBodyEnd - ptrFun);
fclosure = memcpy(fclosure, ptrFun, funBodyEnd - ptrFun);
Y luego cambiar lo que hay dentro de la nueva memoria reservada de tal modo que el valor que queremos referenciar dentro de la función sea otro.
Generalmente en C se suelen utilizar structs para almacenar este tipo de información o bien se tratan de solucionar los problemas utilizando otro método que no requiera closures. Esto hace que el código escrito en C, aunque más rápido y sencillo desde el punto de vista de la máquina, también tienda a ser más largo y complejo de mantener con el tiempo.