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” 馃榾

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 馃檪


M谩s vale tarde que nunca. Extensiones en Safari.

junio 14, 2010

Pese a que toda la atenci贸n del WWDC se la ha llevado el nuevo iPhone, entre el barullo del nuevo tel茅fono de Apple se ha lanzado una nueva versi贸n del navegador por defecto del OSX, estamos hablando de Safari 5.

Una de las grandes novedades del Safari 5 es que incorpora la posibilidad de ejecutar extensiones, de la misma manera que hace Firefox desde hace mucho tiempo, o mas recientemente Chrome, de hecho, el concepto utilizado es muy similar al usado en el navegador de Google.

Adem谩s de para OSX, Safari 5 tambi茅n esta disponible para Windows, y a diferencia de las versiones anteriores y, basado en mis escasas pruebas, parece que es cuanto menos usable. La buena noticia es que las extensiones son totalmente funcionales tambi茅n en el sistema operativo de Microsoft.

Hablando ya de las extensiones de Safari, existen varios tipos. Si hablamos de modificar o a帽adir elementos a la interfaz gr谩fica de Safari, podemos tener nuevos botones, nuevas barras o nuevos elementos que se a帽adir谩n al men煤 contextual. Aparte de estos elementos, podremos tener extensiones que modifiquen la propia web que estamos visitando, como el t铆pico bloqueador de anuncios o de contenidos Flash

Desde el punto de vista t茅cnico, las extensiones estan programadas usando las t铆picas t茅cnologias web; HTML5, CSS3 y Javascript

Entrando un poco mas en detalle, t铆picamente las extensiones estar谩n formadas por una p谩gina HTML que se cargar谩 al incio de la extensi贸n. Esta p谩gina la usaremos para colocar las inicializaciones del resto de componentes, as铆 como los eventos que responder谩n a los elementos gr谩ficos de la propia extension.

Adem谩s de esta pagina web, tendremos seg煤n los requisitos de esta extension, un conjunto de HTML y CSS que controlar谩n el aspecto gr谩fico de nuestra extensi贸n. Por ejemplo, si queremos hacer una barra que muestre algun tipo de informaci贸n, dicha informaci贸n estar谩 descrita por un fichero HTML con su correspondiente hoja de estilo, im谩genes e iconos.

Si, por otro lado, queremos que nuestra extensi贸n modifique el contenido de la web, necesitaremos tener un conjunto de scripts programados usando Javascript, con el que gr谩cias a la API que nos proporciona el navegador (ofrecida en Javascript tamb铆en), podremos acceder e incluso modificar el propio contenido de la web que se esta mostrando en el navegador.

Si queremos ponernos manos a la obra, el propio Safari tiene un editor para crear las extensiones. No esperar encontraros un editor de HTML ni nada parecido, en lo que nos ayudar谩 sera en crear la estructura o el “paquete” en el que podremos meter los contenidos de las propias extensiones. Con el Extension builder podremos crear los botones, barras o scripts de las que hemos hablado anteriormente.

Para activarlo, necesitamos ir al men煤 de preferencias de Safari, y activar el menu de Desarrollador, que por defecto esta desactivado. Una vez activado dicho men煤, podremos acceder al Extension builder

El 煤ltimo elemento que necesitamos para crear la extensi贸n es un certificado de desarrollador. Sin este cerficado no podremos ni siquiera instalar una extensi贸n en nuestro navegador. Como vemos, el concepto es muy similar al seguido con el iPhone.

La principal diferencia, es que formar parte del programa de desarrolladores de extensiones de Safari es totalmente gratis. Lo 煤nico que tenemos hacer es ir a la web de desarrolladores de apple, http://developer.apple.com y darnos de alta.

Despu茅s de rellenar los datos oportunos s贸lo tendremos que instalar el certificado en el llavero de Mac, o en el almacen de certificados de Windows, para que el Extension Builder lo detecte y nos deje instalar y empaquetar nuestra extensi贸n


Medidor de luz en Cocoa usando Arduino

junio 8, 2010

Hace tiempo que no publicaba nada del magn铆fico Arduino. La culpa, como siempre, de que los d铆as s贸lo tengan 24 horas 馃槈

En el anterior post sobre Arduino, presentamos lo f谩cil que era conectar processing con Arduino. En este post vamos a ver que no s贸lo con Processing, realmente leer los datos que nos da el Arduino es f谩cil desde cualquier sitio.

Para presentarlo vamos a mostrar un peque帽o programa hecho en Cocoa que lee los datos recogidos por el Arduino y lo muestra gr谩ficamente.

En primer lugar pondremos el esquema del circuito.

El circuito es bastante sencillo y sin muchos secretos, el 煤nico detalle a tener en cuenta es que utilizamos una resistencia pull-up de 1KOhm para medir la tensi贸n despu茅s del sensor LDR. Esto lo conectamos a la entrada 0 de la placa del Arduino.

De esta manera el arduino leer谩 el valor de esa entrada, pero necesitamos alguna manera para comunicarnos con el PC. Aqu铆 es donde entra la sencillez del Arduino, ya que podemos usar el puerto USB para comunicarnos. Los datos los enviaremos con la librer铆a Serial. Desde el PC, al tratarse de una comunicaci贸n serie, podemos usar cualquier mecanismo para leer del puerto. Y cuando decimos cualquiera, realmente hay un mundo de posibilidades, por mencionar algunos, tenemos librerias en Python, Java o incluso usando la librer铆a estandar de C.

El c贸digo del programa que cargamos en el arduino es el siguiente

int LDR = 0;
int val = 0;
int delayTime = 500;

void setup()
{
  pinMode(LDR, INPUT);
  pinMode(ledPin, OUTPUT);
  Serial.begin(9600);
}

void loop() {
  val = analogRead(LDR);
  Serial.println(val);
  val = 0;
  delay(delayTime);
}

Como vemos es bastante sencillo. En el Setup, configuramos el puerto serie con una velocidad de 9600 baudios y cada lectura la escribimos en el puerto serie usando el Serial.write.

De la misma manera podemos usar el puerto USB para establecer la comunicaci贸n inversa, en algun futuro post veremos como realizarla, y como usar el Arduino como medio para mostrar informaci贸n de forma diferente.

Cuando instalamos el driver de Arduino en nuestro PC, nos crea un dispositivo que variar谩 segun el sistema operativo. En mi caso, OSX, el dispositivo es /dev/tty.usbserial-A900aeKy , por lo que con el programa cargado, podremos leer de ese puerto los datos que esta leyendo la placa del sensor. Para ello podemos usar el programa screen, que viene con la gran mayor铆a de sistemas basados en UNIX.

Si ejecutamos en una terminal el comando

$ screen /dev/tty.usbserial-A900aeKy

Deber铆amos ver algo parecido a esto:

En pantalla podemos ver como van apareciendo los valores que esta leyendo la placa, si variamos la intensidad de la luz, efectivamente vemos como dichos valores cambian.

Una vez que tenemos lista la parte del Arduino, la siguiente parte es crear la aplicaci贸n en PC. Como hemos mencionado antes, para capturar los datos que nos llegan, debemos leer del puerto serie. Para ello, y al estar en un sistema Unix, podemos utilizar la Api est谩ndar para leer de un dispositivo.

Como esto lo vamos a usar desde una aplicaci贸n en Cocoa, vamos a encapsular estas funciones en un objeto de cocoa, de tal manera que su uso sea mas sencillo. Este objeto al construirse abrir谩 el puerto serie, y nos ofrecer谩 un m茅todo para obtener el siguiente valor le铆do.

Hablando del c贸digo en C, como podeis suponer no tiene mucho secreto, usando open() abriremos el fichero que representa el dispositivo, y con read() leeremos los datos.

El enlace al c贸digo fuente esta al final de la entrada, pero el c贸digo principal que realiza esto es algo como lo siguiente:

int fd = open("/dev/tty.usbserial-A900aeKy", O_RDWR | O_NOCTTY | O_NDELAY);
char buffer[100]; memset(buffer, 0, 100);
int nbytes = read(fd, buffer, 100);

La 煤ltima parte que nos falta del puzzle es la aplicaci贸n Cocoa que se encargar谩 de mostrar los datos, la idea es mostrar un numero que indique el valor leido del sensor, y un medidor del tipo NSLevelIndicator para mostrar un indicador gr谩fico del valor del sensor.

No entrar茅 en detalle en comentar la aplicaci贸n en Cocoa ya que es muy sencilla, la aplicaci贸n consta de una Custom View que pinta el n煤mero leido. Para realizar las lecturas periodicas, se utiliza un NSTimer que llamar谩 periodicamente a un m茅todo que le especifiquemos y que se encargar谩 de actualizar la vista con el nuevo dato leido.

Para finalizar el post, os dejo con un video del programa en funcionamiento y el c贸digo de la aplicacion Cocoa y del programa de Arduino.

Codigo Fuente