jueves, 30 de diciembre de 2010

Raros Lenguajes Nuevos: Ela

RSDN

Sobre el final del año inicio una serie que espero continuar desarrollando durante el incipiente 2011: Raros Lenguajes Nuevos.

La idea es dedicar cada tanto un post a algún nuevo lenguaje que aparezca en el radar, no necesariamente de los esotéricos, si no generalmente aquellos con posibilidades interesantes de ganar adopción o servir de campo experimental en ciertas áreas, aportando ideas que se incorporen en otros lenguajes más populares, como ocurre todo el tiempo en este campo.

 

Ela

En palabras de su creador, Vasily Voronkov: "Ela is a strict dynamically typed impure functional language" (un lenguaje funcional impuro, estricto y dinámicamente tipado). Y está implementado para correr sobre el CLR de .NET ó Mono. Analicemos estas características:

Dinámico se refiere a que los tipos se definen y verifican en tiempo de ejecución, no de compilación, y estricto se refiere a que las asignaciones (por omisión) no se difieren, sino que ocurren en el momento. Los tipos son además fuertes, es decir que no hay conversiones implícitas (no se pueden sumar números y strings, por ejemplo).

Exactamente al revés que en Haskell, que es funcional pero no-escricto (o lazy) por omisión, en Ela esta característica es opcional y debe ser explícita. Por ejemplo:

let x =(&2+2)
let y
= x *2//La expresión '2 + 2' se evalúa recién en este momento

El motivo de esto es que Ela está diseñado para ser funcionalmente impuro, también al contrario de Haskell. Esto significa que un programa puede tener efectos colaterales, o más simplemente, mantener estado (usar variables). Los lenguajes funcionales puros solamente admiten constantes y funciones, y no hay estado variable, lo que permite muchas cosas interesantes, pero implica un enorme cambio de mentalidad para cualquier programador que no proviene del mundo de las matemáticas.

Finalmente, la sintaxis general de Ela es relativamente parecida a ML (o el reciente F#), utilizando secuencias, líneas de ejecución y comparación de patrones. Un ejemplo para asustarse (aunque en realidad no es difícil de entender después de algunas reglas básicas, sería:

let filter f x::xs | f x  = x :: filter f xs;
                   
|else= filter f xs;
           _
[]           =[]

Esto define una función filter que recibe un predicado, es decir una función que evalúa cada elemento en una lista para filtrarla. El uso de esta función para filtrar los elementos mayores que 5 es tan sencillo como:

let filter' = filter (>5)

Como siempre en programación funcional, se trata principalmente de describir el resultado a obtener más que detallar los pasos a seguir para obtenerlo, y Ela sigue bien esta tradición.

¿Qué diferencia a Ela de otros lenguajes?

Además de características funcionales típicas como funciones anónimas (lambdas) y closures, y aplicación parcial.

Sin embargo, Ela toma un decisión interesante respecto de cualquier otro lenguaje (que yo haya visto), y es que toda función debe recibir un único parámetro. No cero ni más de uno. Esto que parece bastante restrictivo se resuelve en forma general haciendo que una función reciba otra, generando encadenamiento, como en:

let res = sum 23// por supuesto, devuelve 5

pero no recibe dos parámetros, sino que sum recibe como entrada 2 y devuelve una función anónima que recibe como parámetro el 3. Veamos la definición de sum:

let sum x y = x + y

Esta es una técnica conocida como currying(que toma su nombre del matemático Haskell Curry, al igual que el lenguaje Haskell que toma la otra mitad). En programación funcional esta es una técnica muy usual para componer funciones, pero no es obligatoria.

A primera vista parece raro, si, pero el hecho de pensar que toda función recibe un único parámetro cambia por completo la sintaxis del lenguaje, ya que no hacen falta más paréntesis ni separadores, y esto tiene un montón de consecuencias interesantes de analizar (y obviamente plantea varios desafíos).

Otra interesante decisión de diseño es que todos los operadores son identificadores únicos, con lo que no hay posibilidad de utilizar un símbolo con diferente semántica en dos contextos. Por ejemplo, el operador "-" (signo menos) significa resta, por lo que el operador unario para indicar un número negativo es "--" (por ejemplo: --2). Raro otra vez, pero hay algunas razones válidas relativas a la capacidad de validación de expresiones en cualquier contexto.

Es importante destacar que aunque el intérprete es totalmente funcional y puede ser embebido en código .NET o Mono, el proyecto está aún en nivel experimental.

Para los interesados, la documentación más completa por ahora es la Wiki en Google Code (en inglés), o este artículo del autor (en ruso).

 

miércoles, 29 de diciembre de 2010

Node.js: simplicidad y eficiencia

node.JS

Desde hace tiempo tenía pendiente escribir sobre Node.js (Node para los amigos). Hago una breve introducción primero para que se entienda por qué me parece importante:

Hace ya un par de años escribí un post hablando del resurgimiento de Javascript como lenguaje en todos lados, y la tendencia que veía entonces está empezando a ser notoria este año y creo que se va a afianzar el próximo.

El primero paso hacia un mayor uso de Javascript del lado del servidor fue la aparición de CommonJS como iniciativa para unificar detalles de las diferentes implementaciones, y es algo que está ganando bastante aceptación, especialmente en el soporte para los modules.

Node inició fuera de este estándar, pero luego se adaptó a CommonJS, y es un motor de Javascript del lado del servidor fuertemente basado en eventos y orientado principalmente a un manejo eficiente de comunicaciones en red. Se basa a su vez en el motor de Javascript V8, creado por Google y utilizado en Chrome, pero publicado como código abierto. Node también es código abierto con ncia MIT.

Lo notable de Node es que aprovecha la característica de Javascript como lenguaje y cultura, que a diferencia del resto del universo de la programación, siempre vio como algo natural el hacer llamadas no-bloqueantes.

Veamos la diferencia. Mientras en otros lenguajes cosas triviales como una consulta tienden a escribirse naturalmente como:

resultado = query( 'select * from Tabla');

en Javascript lo usual sería expresar esto como:

query( 'select * from Tabla', function (resultado) {
   // y aquí vemos qué hacemos con el resultado...
});

¿Cuál es la diferencia principal? Que la primer manera de llamada es bloqueante; es decir que mientras el resultado de la consulta no llega, el programa está detenido. En el segundo ejemplo, la llamada es no bloqueante, por lo que el resultado no se asigna a una variable sino que se pasa como parámetro a un callback (una función que será llamada al terminar la ejecución de la consulta, en este caso). En el ejemplo el callback se define en el mismo lugar para abreviar, pero podría ser una función definida en otra parte.

Lo importante de esta diferencia es que el estilo bloqueante de llamadas consume muchísimos recursos mientras se produce esa espera, que al involucrar acceso a disco o recursos de red puede ser por un tiempo importante, sobre todo al considerar una ambiente de alta concurrencia.

El modelo no-bloqueante o asincrónico, permite además manejar el procesamiento de esos callbacks dentro de un bucle de atención de eventos en lugar de necesitar threads separados para cada instancia. Y los threads son costosos y cuello de botella a la hora de escalar con mucha concurrencia.

Node aprovecha esta diferencia cultural de Javascript y brinda un entorno donde podemos realizar la mayor parte de las conexiones de red en forma no-bloqueante.

Veamos un ejemplo rápido que puede ilustrar la sencillez y eficiencia de Node en acción:

http = require('http');
Buffer = require('buffer').Buffer;
mega = 1024 * 1024;
bloque = new Buffer(mega);
for (var i=0; i<mega; i++) bloque[i] = 65; // Letra "A"
// SERVIDOR
http.createServer( function (pedido, respuesta) {
respuesta.writeHead(200);
respuesta.end(bloque);
}).listen(8000);

Las últimas cuatro líneas son la versión más básica de un web server en Node. ¿Sencillo, verdad?

Las primeras dos líneas utilizan el mecanismo de CommonJS de inclusión de módulos. El módulo HTTP permite acceso completo al protocolo como cliente o servidor y soporta cosas interesantísimas como la capacidad de devolver contenido como streaming. El módulo Buffer se utiliza para preparar bloques de datos binarios o crudos, no Unicode.

Las siguientes tres líneas solamente crean ese bloque de 1 Megabyte exacto de largo.

Lo más interesante son esas últimas cuatro (una sola sentencia, como se puede apreciar). Allí creamos una instancia del servidor web que atenderá en el puerto 8000 y al recibir cualquier pedido (HTTP request) responderá el bloque lleno con 1 Mb de letras A con status Ok (200) en la cabecera.

Pero lo más interesante es la manera en que se comporta el servidor si lo sometemos a una prueba de alta concurrencia. En pruebas con 100 requests concurrentes, Node llega a responder más de 800 requests por segundo (respondiendo 1 Mb para cada uno), lo que es un rendimiento asombroso. Estas características brillan en servicios de chat, presencia, colaboración o cualquier otro escenario donde típicamente deban soportarse muchas conexiones concurrentes.

Node tiene muchas otras ventajas, pero espero que hasta acá alcance para interesarlos. Lo ideal para conocer más sobre Node, además del sitio oficial, es la comunidad de artículos sobre usos y extensiones How to Node.

martes, 28 de diciembre de 2010

Kod: un editor de código (abierto) para OS X

Kod

Kod es un editor orientado a escribir código para OS X. Es de código abierto, bajo licencia MIT (modificada para no permitir vender el editor como tal) y alojado en GitHub.

Tiene algunas características muy interesantes, que me llamaron la atención y por lo que estoy empezando a usarlo con bastante buen resultado (listo lo que detallan en el sitio oficial, con mis comentarios):

  • Tiene un comportamiento muy asincrónico, y aprovecha el poder de los procesadores de múltiples núcleos que tenemos hoy día. Esto es algo que hace tiempo espero de más aplicaciones.¿Porqué tengo que esperar a que las cosas se terminen de grabar para poder seguir trabajando? Kod es muy eficiente al estar trabajando con múltiples archivos de diferentes tamaños.
  • El entorno de scripting está basado en el ascendente Node.js, sobre lo que tengo que escribir un próximo post en más detalle.
  • Interfaz de usuario inspirada en Chromium, utilizando tabs que pueden soltarse en ventanas independientes y volverse a unir, pero sobre todo, permitiendo escribir el nombre del archivo a editar directamente en la barra de direcciones, algo que es muy práctico al editar código, en lugar de tener que abrir un cuadro de diálogo.
  • Tiene algunas cosas que no usé, como que permite editar directamente archivos a través de HTTP (aunque no grabarlo, claro), y para cambiar estilos en el editor todo se hace mediante CSS 3.
  • Soporta al parecer 65 lenguajes o dialectos, y al menos tiene buen soporte para Ruby, JScript y Python por lo que vi hasta ahora.

Atención: para los que buscar una IDE, este es sólo un editor. Pero es muy interesante, parece ser activamente mantenido, y puede ser una competencia interesante a los tradicionales TextMate y Vim habituales en el mundo Mac.

Dejo como muestra una captura del editor en mi máquina:

Kod-screen