Closures en C y Objective-C

junio 30, 2010

Si, aunque intenteis leer otra vez el título del post, vamos a hablar de, las tan de moda, closures para C. :)

Sin duda, dada la naturaleza de C, se hace extraño que se añadan funcionalidades que normalmente se asocian a lenguajes mas modernos (o aún en evolución) como C#, Java o otros lenguajes de script como Python o Ruby

El nombre elegido para referirnos es “blocks”, y básicamente ha sido un añadido de Apple al compilador GCC que usamos en Mac y al futuro CLang que corre sobre el también futuro y prometedor LLVM.

Por el momento esta extensión de C no es estandar, y dada la cerrada naturaleza de los estándares de C es complicado que llegue a serlo. Pero, por otro lado, al estar implementado en compiladores como GCC o en el frontend de LLVM Clang, y además, al ser estos compiladores opensource y portables entre diferentes plataformas, presumiblemente esta extensión se pueda utilizar sin problemas en el futuro, al igual que usamos ciertas extensiones propias de GCC que tampoco forman parte de los estandares de C.

Apple desarrolló los blocks como parte de la tecnologia “Grand Central Dispatch”. Esta tecnologia optimiza ciertos bloques de ejecución, y como podeis esperar, el “empaquetar” los bloques de ejecución usando esta extensión del lenguaje facilita mucho la gestión por parte del sistema operativo y la programación por parte de los desarrolladores.

Hasta ahora hemos estado hablando alegremente de closures, básicamente los closures es una forma de encapsular un comportamiento bajo una variable. Usando esta variable podemos manejar el comportamiento (o función) de la misma manera que manejamos el resto de variables, esto es, por ejemplo, pasarlo como parámetros a una función.

Como siempre, lo mejor es verlo con un ejemplo, antes de adentrarnos en C,vamos a ver un ejemplo en Javascript. Lo bueno de este lenguaje es que la sintaxis es muy sencilla y nos va a permitir ver el concepto mas fácilmente.

funcion_suma = function(a,b) { return a+b; }
funcion_resta = function(a,b) { return a-b; }

function opera(op1, op2, operacion) {
	return operacion(op1, op2);
}

opera(3, 2, funcion_suma);
  // Imprime 5
opera(3, 2, funcion_resta);
  // Imprime 1
opera(3, 2, function(a,b) {
	return a*b;
});
  // Imprime 6

En el ejemplo creamos dos variables asignadas a funciones, que realizan las diferentes operaciones, y estas variables se las pasamos a la funcion “opera”. Cuando desarrollamos la funcion “opera” no sabemos que operación vamos a realizar, dejamos esa puerta abierta para que cada cliente de la función aporte su propia función de operación. Como vemos en el último caso, podemos definir la propia función cuando construimos los parámetros de la llamada.

La gran ventaja de esta técnica es la extensibilidad, ya que dejamos total libertad para que el desarrollador aporte la función a la que se va a llamar. Este ejemplo es muy sencillo, pero al final del post veremos puntos de Cocoa donde se estan usando los blocks y veremos de forma mas clara en que son una ventaja.

Centrandonos ya en C, Apple ha escogido el simbolo ^ para marcar un bloque. Es curioso ya que este simbolo se utilizaba en otra extension de C++ por parte de Microsoft para marcar cierto tipo de variables cuando se desarrolla con Managed C++.

Por lo tanto, para definir un bloque en C, usamos el simbolo ^, seguido de la lista de parámetros entre parentesis y después el bloque de codigo que conforma el bloque. Para definir el tipo del bloque usamos el tipo de retorno, el nombre del bloque entre parentesis y precedido de ^ y finalmente la lista de parámetros entre parentesis. Aunque pensandolo bien todo este parrafo me lo podría haber ahorrado, simplemente poniendo un ejemplo ;)

int (^funcion_suma)(int, int) = ^(int a, int b) { return a + b; };

Siguiendo la linea anterior, esta sería la forma de declarar una variable de tipo “funcion_suma” al igual que haciamos en javascript. Como vemos, la sintaxis es realmente mas compleja que la de javascript.

int opera(int op1, int op2, int (^funcion_opera)(int, int)) { return funcion_opera(op1, op2); }

opera(3, 2, funcion_suma);
  // Imprime 5
opera(3, 2, ^(int a, int b) {
	return a * b;
})
  // Imprime 6

Y aquí tenemos la anterior versión de la función “opera” pero en C, como vemos el concepto es similar, pero con una sintaxis mas enrevesada.

Si habeis programado en otros lenguajes como Java, la ultima invocación os sonara a clases anonimas, y ciertamente se les parece bastante. Al igual que con estas clases los blocks tienen suelen ser un buen sustituto a la hora de crear un callback. Una ventaja con respecto a la forma tradicional de implementar dichos mecanismos, es que pueden acceder a las variables locales del entorno donde se estan ejecutando. Esto es bastante util en numerosas ocasiones, usando blocks nos ahorraremos tener que pasar dichos datos a la funcion u objeto que implemente el callback.

Para marcar que una variable va a ser accedida dentro de un bloque, usamos el modificador __block antes de la variable que va a ser accedida dentro del bloque. Como por ejemplo:


__block int multiplicador = 6;

opera(3, 2, ^(int a, int b) {
	return a * b * multiplicador;
})
  // Imprime 36;

A partir de iOS 4 en el iPhone y OSX 10.6 los bloques son una realidad en Cocoa y Cocoa Touch. Poco a poco van apareciendo métodos que soportan un bloque para indicar el comportamiento de una acción.

Un ejemplo, sacado de la documentación de apple es método sortedArrayUsingComparator: del NSArray. El uso tradicional de este funcionalidad seria pasandole un puntero a función que resuelva la comparación, como podemos ver en sortedArrayUsingFunction:context:. Como hemos visto anteriormente, dada a la limitación de este método, Cocoa nos proporciona un puntero a nuestros datos, reflejado en el parámetro context.

Si usamos bloques en este caso, nos saltamos esta limitación, y además, facilita la lectura del código ya que podemos poner la lógica del comparador en la misma llamada de la función.

Para finalizar el post, vamos a ver un ejemplo de una ordenación de un Array usando bloques y sin usarlos

Usando el método tradicional, la ordenación del array quedaría algo como:

NSInteger alphaComparator(id arg1, id arg2, void* arg3) {
  NSString *a = (NSString*)arg1;
  NSString *b = (NSString*)arg2;
  return strcmp([a cStringUsingEncoding:[NSString defaultCStringEncoding]],
				[b cStringUsingEncoding:[NSString defaultCStringEncoding]]);
}

int main (int argc, const char * argv[]) {
  NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];

  NSArray *stringsArray = [NSArray arrayWithObjects:
    @"Roberto",
	@"Alfonso",
	@"Ruben",
	@"Mariano",
    @"Juan",
	@"Antonio",nil];

  NSArray* sortedArray = [stringsArray
			sortedArrayUsingFunction:alphaComparator context:nil];
  for ( NSString* cad in sortedArray ) {
    NSLog(@"%@\n", cad);
  }

  return 0;
}

Por otro lado, usando bloques quedaría algo como:

iint main (int argc, const char * argv[]) {

  NSArray *stringsArray = [NSArray arrayWithObjects:
   @"Roberto",
   @"Alfonso",
   @"Ruben",
   @"Mariano",
   @"Juan",
   @"Antonio",nil];

  NSArray* sortedArray = [stringsArray sortedArrayUsingComparator:^(id str1, id str2) {
    NSString *a = (NSString*)str1;
	NSString *b = (NSString*)str2;
	return (NSComparisonResult)
			strcmp([a cStringUsingEncoding:[NSString defaultCStringEncoding]],
				  [b cStringUsingEncoding:[NSString defaultCStringEncoding]]);
  }];

  for ( NSString* cad in sortedArray ) {
	NSLog(@"%@\n", cad);
  }

  return 0;
}

Sin duda, bajo mi punto de vista la solución usando bloques es mucho mas elegante, pese a que el enfrentamiento inicial con los blocks pueda ser algo “dura” :D

Como conclusión, simplemente decir que es muy grato ver como se van añadiendo funcionalidades a nuestro lenguaje favorito y, de esta manera, adaptandolo un poco mas a los tiempos en los que vivimos :)


Los peligros de devolver punteros

noviembre 3, 2009

 

Cuando escoges un lenguaje que deja en tus manos la gestión de memoria tienes que tener mucho cuidado con la manera en que gestionas los recursos que están a tu disposición. Si bien es cierto que puedes tener mucha flexibilidad a la hora de manejar la forma en que pasas los datos a tus funciones o métodos, esa flexibilidad se convierte en responsabilidad a la hora de liberar de forma correcta lo que en algún momento reclamas.
Por norma, siempre es buena idea que algún punto de nuestro programa se haga responsable de la memoria que el mismo pide, de esta manera sabrá como y cuando liberarlo. Por ejemplo, si una función necesita pasar un espacio de memoria a otra función para que escriba en ella, la mejor idea es que la función cree el espacio y se lo pase a la función de lectura ya creado, de tal maneras que cuando lo use, sea capaz de eliminarlo sin problemas.
void f1()
{
  ...
  char* buffer = new char[100];
  f2(buffer);
  ...
  delete [] buffer;
  ...
}
Uno de los diseños que pueden inducir a problemas es el hecho de que una función devuelva un puntero a una memoria de la que dicha función pierde la responsabilidad. Por ejemplo
char* f2()
{
  char* buffer = new char[100];
  ...
  return buffer;
}
Este diseño, puede ocasionar que la memoria de buffer nunca sea liberada, por ejemplo, si usamos la llamada como parametro de otra función, esa memoria nunca se liberará, o bien por que directamente se nos olvide liberar la memoria que no hemos reservado en la función original, por ejemplo:
void f1()
{
  int len = strlen(f2()); // la memoria de f2 no es accesible
}
En este ejemplo vemos como la memoria que f2() ha reservado, nunca se libera, pues no hay ninguna variable que la referencie y que podamos usar para liberarla.

 


¿Qué es la metaprogramación?

octubre 12, 2009
En los últimos meses he estado cada vez mas ligado a C++, realmente no me pilla de nuevas pero si es cierto que en los ultimos tiempos mi produccion de codigo ha sido casi enteramente en Java.
La vuelta a C++ no me ha sentado nada mal, de hecho, he agradecido el dejar de hacer las mismas típicas aplicaciones de “Altas/Bajas/Modificaciones/Consultas”
En el refresco de C++, pude tener acceso a un libro que me prestó un compañero de trabajo. El libro en cuestión es “Modern C++ Design: Generic Programming and Design Patterns Applied” (http://www.amazon.com/Modern-Design-Generic-Programming-Patterns/dp/0201704315) de Alexei Alexandrescu. De momento solo he leido algunas paginas pero me ha servido para descubrir un mundo que hasta ahora no había explorado, la metaprogramación.
Es difícil simplificar algo como la metaprogramación en una sola frase, en una primera impresión, y como su propia palabra indica, es la programación sobre la programación, o también se puede ver como programas que construyen programas. Uno de los principales objetivos de esta técnica es llevar a tiempo de compilación cálculos que habitualmente se hacen en tiempo de ejecución.
Un claro ejemplo podría ser la construcción de una tabla de resultados, por ejemplo, si en nuestro programa necesitamos hacer una operación costosa, digamos una función matemática que exija mucho tiempo de cálculo, en lugar de llamar a dicha función en tiempo de ejecución, crearemos un código cuya salida sea los valores de esa función evaluada para diferentes valores y que sea usable desde nuestro programa, por ejemplo como la inicialización de un array con dichos valores.
== Ejemplo clásico ==
double funcion_costosa (int valor)
{
/* … */
}
cout << funcion_costosa(3);
== Ejemplo con técnicas de metaprogramación ==
double[] valores = {1.7862, 1.7652, 1.7890, 1.7675,….}; // Código generado con metaprogramming
cout << valores[3];
Como se puede ver en el ejemplo, si la optimización es nuestro objetivo, cuanto vamos a ganar usando técnicas de metaprogramacion en nuestros programas.
Ahora la pregunta es…¿y como puedo hacer eso? Realmente hay muchas técnicas para conseguir generar código, depende de la plataforma donde nos encontremos. La mayoría de estas técnicas recaen en preprocesadores o en los propios compiladores, concretamente en C++ una de las maneras de conseguirlo es usando plantillas.
Si algo me ha descubierto el libro que mencionaba al principio de la entrada es principalmente la flexibilidad y la potencia que tienen los “templates” en C++.
Un ejemplo habitual de metaprogramación en C++ usando plantillas suele ser el calculo de una serie de números, como por ejemplo el factorial, la serie de fibonacci o como vemos en el siguiente ejemplo, el desarrollo de la serie para calcular el valor de la función trigonometrica “seno”

En los últimos meses he estado cada vez mas ligado a C++, realmente no me pilla de nuevas pero si es cierto que en los ultimos tiempos mi produccion de codigo ha sido casi enteramente en Java.

La vuelta a C++ no me ha sentado nada mal, de hecho, he agradecido el dejar de hacer las mismas típicas aplicaciones de “Altas/Bajas/Modificaciones/Consultas”

En el refresco de C++, pude tener acceso a un libro que me prestó un compañero de trabajo. El libro en cuestión es “Modern C++ Design: Generic Programming and Design Patterns Applied” de Alexei Alexandrescu. De momento solo he leido algunas paginas pero me ha servido para descubrir un mundo que hasta ahora no había explorado, la metaprogramación.

Es difícil simplificar algo como la metaprogramación en una sola frase, en una primera impresión, y como su propia palabra indica, es la programación sobre la programación, o también se puede ver como programas que construyen programas. Uno de los principales objetivos de esta técnica es llevar a tiempo de compilación cálculos que habitualmente se hacen en tiempo de ejecución.

Un claro ejemplo podría ser la construcción de una tabla de resultados, por ejemplo, si en nuestro programa necesitamos hacer una operación costosa, digamos una función matemática que exija mucho tiempo de cálculo, en lugar de llamar a dicha función en tiempo de ejecución, crearemos un código cuya salida sea los valores de esa función evaluada para diferentes valores y que sea usable desde nuestro programa, por ejemplo como la inicialización de un array con dichos valores.

== Ejemplo clásico ==

double funcion_costosa (int valor)
{
   /* ... */
}
cout << funcion_costosa(3);

== Ejemplo con técnicas de metaprogramación ==

double[] valores = {1.7862, 1.7652, 1.7890, 1.7675,....}; // Código generado con metaprogramming
cout << valores[3];

Como se puede ver en el ejemplo, si la optimización es nuestro objetivo, cuanto vamos a ganar usando técnicas de metaprogramacion en nuestros programas.

Ahora la pregunta es…¿y como puedo hacer eso? Realmente hay muchas técnicas para conseguir generar código, depende de la plataforma donde nos encontremos. La mayoría de estas técnicas recaen en preprocesadores o en los propios compiladores, concretamente en C++ una de las maneras de conseguirlo es usando plantillas, y basándonos en técnicas como la especialización parcial y la recursividad.

Si algo me ha descubierto el libro que mencionaba al principio de la entrada es principalmente la flexibilidad y la potencia que tienen los “templates” en C++.

Un ejemplo habitual de metaprogramación en C++ usando plantillas suele ser el calculo de una serie de números, como por ejemplo el factorial, la serie de fibonacci o como vemos en el siguiente ejemplo, el sumatorio de los N valores:

template <int N>
struct Sumatorio
{
enum { result = N + Sumatorio<N-1>::result };
};
template <>
struct Sumatorio<0>
{
enum { result = 0 };
};
int sumatorio(int n) {
 return (n==0)? 0 : (n + sumatorio(n-1));
}
...
cout << Sumatorio<10>::result
...

Al compilar este ejemplo, el compilador se encargará de realizar la sustitución recursiva, de tal manera que en el código compilado la expresion Sumatorio<10>::result sera sustituido por “55″. Como vemos, la diferencia con realizar la llamada a la función sumatorio() es que si usamos templates, en tiempo de ejecución no se utilizará ni un ciclo de computación en calcular dicho sumatorio.

Si bien es cierto que mecanismos como estos tienen algunos inconvenientes como que por ejemplo hacen el código mas complicado de entender, desde el punto de vista del programador entrañan un bonito reto a acometer, cuyo principal objetivo puede ser la optimización. En mi opinión estos mecanismos añaden un poco de “picante” a la, a veces, monótona labor de programación.


Los inconvenientes de mezclar dos mundos

septiembre 7, 2009


En Muchas ocasiones cuando vemos las letras C++ o C, realmente no nos damos cuento de cuanto diferentes son ambos mundos. El facil acceso a C desde C++ sin duda es una gran ventaja ya que por una parte nos permite acceder a la gran funcionalidad que C ha adquirido en todos estos años y por otro lado nos permite utilizar el gran número de librerías que existen para el lenguaje de programación más común.

En el gran y “tedioso” libro sobre C++ de Bjarne Stroustrup, podemos encontrar las razones de porque cuando pensaba en crear un nuevo lenguaje de programación, pensó en C. Sus principales razones fueron: “C puede compilarse y ejecutarse en casi cualquier dispositivo electrónico”.

Sin embargo como vamos a ver en este post, C y C++ realmente son mundos muy diferentes.

Esto viene a cuento por un problema con el que me he topado recientemente, y que me ha dado algún que otro quebradero de cabeza.

Supongamos que tenemos una librería diseñada para ser usada en C. Dicha librería permite hacer llamadas asíncronas, de tal manera que a la función que realiza el proceso debemos pasarle un puntero a función con la dirección a la que llamara cuando la accion se termine, lo que normalmente se conoce como callback. Pongamos como ejemplo, una funcion de lectura de datos.

lib_read(int handle, int waitTime, int (*read_callback)(void *buffer, int sizeRead) );

El prototipo de la función de callback sería algo como:

int my_callback(void *buffer, int size)
{
/* CODIGO */
}

El funcionamiento normal sería realizar la llamada de la siguiente manera:

read(my_handle, 1000 /*ms*/, my_callback);

Hasta aquí, todo correcto. Cuando el proceso haya leído los datos, se llamara a la función my_callback con los datos listos para ser procesados.

Os preguntareis, ¿Cual es el problema?
Como decía anteriormente, vamos a introducir a C++ en la ecuación.
Digamos que tenemos una clase que se encarga de realizar las lecturas de esos datos que hablabamos anteriormente. El ejemplo serÌa algo como:

class ReadHandler
{
public:
ReadHandler();
vector ProcessData();
private:
char* readData;
int read();
/*Teorica funcion de callback para la libreria de lectura */
int my_callback(void* buffer, int size);

}

El objetivo de esta clase es leer los datos y procesarlos, de tal manera que cuando llamamos a ProcessData nos devolverá un array con los datos ya procesados. Gracias al diseño orientado a Objectos de C++, los datos están encapsulados en su clase. Y si creamos varias instancias de ReadHandler, los datos no se compartirán.

Como hemos visto que la librería anterior se ajusta a nuestras necesidades, por lo que nos planteamos usarla para nuestro programa.
Para ello pensamos que el constructor de la clase puede ser un buen lugar para realizar la llamada asincrona, asi cuando nos llamen a ProcessData, si el callback ya ha rellenado los datos contenidos en readData los podamos procesar y devolver su contenido.

Con todo organizado en nuestra cabeza nos ponemos manos a la obra. Añadiremos la función de callback a la clase, y en el constructor la llamaremos

lib_read(handle, 1000, my_callback);

Compilamos y…. error. Todo parece correcto y aun así falla, ¿por qué?. Bienvenidos al mundo de C :)

En la función le estamos pasando un puntero a función, y en C++, no es posible pasar de esa manera un puntero a una función miembro de la clase, como my_callback es, por lo que este será nuestro primer error, seguramente el mas sencillo de solucionar, ya que es el compilador quien se queja.

En C++, para crear un puntero a función miembro se debe usar el operando & precediendo al nombre, aún así, el compilador vuelve a fallar, ya que no es posible pasar un puntero a una función miembro no estática.

Esto nos deja un poco fuera de juego, ya que la librería era perfecta para nuestras necesidades y oye, al fin y al cabo C++ puede usar código C. El problema real es que la convención de llamadas a funciones en C y en C++ es diferente, en C++ aunque no se vea a ojos del programador, el primer parámetro de todas las funciones es un puntero a la instancia sobre la cual llamamos la función, lo que se conoce como la convención thiscall.

La siguiente aproximación puede pasar por abandonar temporalmente C++ y ya que la función necesita como callback, una función estática o una función que no sea de C++, pues podríamos usar una función de C.

El problema de esta aproximación es volver al “mundo” de C++, si el callback seria una función fuera de cualquier clase, no tendríamos una referencia a la instancia que llamo originalmente a la función que realiza la lectura asíncrona.

Llegados a este punto, hemos visto la problemática que tiene la situación, y de hecho este problema no tiene una solución elegante, pues se necesita que la librería proporcione un medio para pasar la instancia que le esta llamando.

Una solución bastante poco elegante pero que puede salvar alguna situación limite es usar una variable global para almacenar la instancia que llama a la función, y así poder hacer la llamada de vuelta.
En código sería algo como:

ReadHandler* global;
ReadHandler::ReadHandler()
{
global = this;
lib_read(…., callback_c);
}

int callback_c(…)
{
this->my_callback(…);
}

Sin duda, esta solución esta plagada de problemas, por ejemplo, ¿Qué pasaría si varios hilos crean instancias de ReadHandler?, pues como podemos predecir, habría un conflicto ya que la variable global no tendría un valor valido en cada llamada.

Dado a este problema y ya que es habitual utilizar librerías de C en C++, el diseño de este tipo de llamadas de forma correcta es crítico, y la mayoría de ellas habilita una variable donde se puede enviar la instancia que realiza la llamada. Por ejemplo, en la API de Windows nos encontramos con funciones con este prototipo

HANDLE WINAPI CreateThread( LPSECURITY_ATTRIBUTES lpThreadAttributes,
SIZE_T dwStackSize,
LPTHREAD_START_ROUTINE lpStartAddress,
LPVOID lpParameter,
DWORD dwCreationFlags,
LPDWORD lpThreadId );

Esta función crea un Hilo, llamando a la función en el parametro lpStartAddress, y pasandole como parametro el que le indicamos en lpParameter. El protipo del callback es:

DWORD WINAPI ThreadProc(LPVOID lpParameter );

Usando esta convención, en nuestro ejemplo:

ReadHandler::ReadHandler()
{
CreateThread(….,callback_compatible, (LPVOID) this, …. );
}

DWORD WINAPI callback_compatible(LPVOID lpParameter)
{
ReadHandler* rh = (ReadHandler) lpParameter;
this->my_callback(……);
}

Muchas librerías ya tienen esto en cuenta, y si estas desarrollando una librería deberias tenerlo en cuenta, ya que no es ningun esfuerzo extra y ganaras la compatibilidad con otros lenguajes como c++.



Seguir

Get every new post delivered to your Inbox.