miércoles, noviembre 11, 2009

El tutorial más corto sobre Autoconf y Automake

Traducción del artículo de Paolo Bonzini (2 de Noviembre del 2009).

El problema con autotools es que se usa para cosas complicadas, y los programadores copian y pegan cosas complicadas aún cuando deben hacer algo simple. El 99% de los programadores sólo necesita acceder a los archivos .pc y generar sencillos Makefiles. De la parte de la portabilidad se encarga glib, sdl, etc.

Se puede usar los siguientes archivos autotools, de sólo 9 líneas, para comenzar desde allí y agregar más cosas luego (incluyendo libtool).
  • configure.ac:
AC_INIT([package], [version])
AM_INIT_AUTOMAKE([foreign subdir-objects])
AC_CONFIG_SRCDIR([configure.ac])
AC_CONFIG_HEADERS([config.h]) # no es realmente necesario
AC_PROG_CC # o AC_PROG_CXX
AC_CONFIG_FILES([Makefile])
AC_OUTPUT
  • Makefile.am:
bin_PROGRAMS = hello
hello_SOURCES = hello.c

Suficiente para ejecutar:

$ autoreconf -fvi
$ ./configure
$ make

Para cada paquete que se necesite, se debe agregar:

PKG_CHECK_MODULES([cairo], [cairo])
PKG_CHECK_MODULES([fontconfig], [fontconfig])

y

AM_CFLAGS = $(cairo_CFLAGS) $(fontconfig_CFLAGS)
LIBS += $(cairo_LIBS) $(fontconfig_LIBS)

respectivamente en configure.ac (luego de AC_PROG_CC) y Makefile.am.

lunes, noviembre 09, 2009

El juego más fácil del mundo

Hace unas semanas escribí sobre el juego más difícil del mundo. Para los que se frustraron intentando pasar algún nivel, acá les traigo otro para saciar la sed de revancha...

sábado, noviembre 07, 2009

Java Hashing

Fuente: Dos Ideas

Escrito por Leonardo De Seta
Martes 27 de Octubre de 2009 10:22

EqualsTodos los objetos en Java tiene dos métodos muy importantes: el método hashCode() y el método equals(). Estos métodos están diseñados para ser sobreescritos de acuerdo a su contrato general.

En este artículo veremos porqué y cómo sobreescribir el método hashCode() que cumpla con el contrato para los HashCode.

El contrato de un HashCode

El contrato del hashCode() dice:

"Si dos objetos son iguales usando equals(), entonces la invocación a hashCode() de ambos objetos debe retornar el mismo valor"

Entonces, la pregunta que surge es: ¿es necesario que siempre se cumpla esa oración?

Consideremos una clase que tiene una implementación correcta del método equals(), ¿qué pasaría si no obedecemos el contrato anterior?

Para responder a esa pregunta, vamos a tener que considerar dos situaciones:

  1. Objetos que son iguales, pero retornan diferentes hashCodes
  2. Objetos que no son iguales, pero retornan el mismo hashCode

Objetos que son iguales, pero retornan diferentes hashCodes

¿Qué pasaría si dos objetos son iguales (invocando equals()) pero retornan diferentes hashCodes? El código se ejecutará a la perfección. Nunca vamos a encontrar problemas... hasta que se nos ocurra almacenar a nuestro objeto dentro de una colección como un HashSet o un HashMap. Cuando hagamos esto, nos vamos a encontrar con problemas raros durante la ejecución.

Primero tenemos que comprender cómo funcionan las clases del tipo HashSet y HashMap. Estas clases de colecciones dependen de que los objetos que son agregados cumplan con el contrato del hashCode. Vamos a obtener resultados impredecibles en tiempo de ejecución si no obedecemos el contrato y queremos almacenar estos objetos en la colección.

Veamos por ejemplo el HashMap. Cuando guardamos valores en un HashMap, estos valores en realidad se almacenan dentro de "baldes". Cada uno de estos baldes tiene asignado un número que lo identifica. Cuando agregamos un valor al HashMap, almacena el dato en uno de esos baldes. El balde que se usa depende del hashCode que devuelva el objeto a ser almacenado. Por ejemplo, si el método hashCode() del objeto retorna 49, entonces se almacena en el balde 49 dentro del HashMap.

Más tarde, cuando verifiquemos si la colección contiene al elemento invocando el método contains(elemento), el HashMap primero obtiene el hashCode de ese "elemento". Luego buscará el balde que corresponde a ese hashCode. Si el balde está vacio, significa que el HashMap no contiene al elemento y devuelve false.

Si hay un objeto o más dentro del balde, entonces se compara al "elemento" con todos los elementos en ese balde usando el método equals().

Objetos que no son iguales, pero retornan el mismo hashCode

El contrato del hashCode no dice nada sobre este caso. Por lo tanto, objetos distintos pueden devolver el mismo hashCode, pero las colecciones como los HashMap van a ser más ineficientes si se almacenan objetos diferentes con el mismo valor de hashCode.

¿Por qué almacenar en baldes?

Se utiliza este mecanismo de "baldes" por un tema de eficiencia. Pueden imaginarse que si todos los objetos que se agregan a un HashMap se almacenaran en una única lista grande, entonces tendríamos que comparar la entrada con todos los objetos de la lista para dterminar si un elemento en particular está contenido en el Map. Como se usan baldes, sólo se comparan los elementos del balde específico, y en general cada balde sólo almacena una pequeña cantidad de elementos en el HashMap.

Sobreescribir el método hashCode()

Puede resultar complejo escribir un buen método de hashCode() para una clase nueva.

Retornar un valor fijo (es una mala idea...)

Podemos implementar un método de hashCode() que devuelva un valor fijo, como por ejemplo:


//no hagan esto, genera mal rendimiento
@Override
public int hashCode() {
return 1;
}

Este método satisface todos los requerimientos y es "legal" de acuerdo al contrato del hashCode, pero no va a resultar muy eficiente. Si se usa este método, todos los objetos se almacenarán dentro del mismo balde (el correspondiente al "1"), y cuando querramos comprobar si un objeto específico está dentro de la colección, entonces siempre se tendrá que verificar el contenido completa de dicha colección.

Por otro lado, si sobreescribimos el método hashCode() y rompemos el contrato ("dos objetos iguales con equals deben devolver el mismo hashCode"), entonces cuando se invoque el método contains() podría devolver false para un elemento que se encuentra dentro de la colección, pero en un balde diferente.

Método de Effective Java

Joshua Bloch en su libro Effective Java nos brinda una buena guía para generar un valor de hashCode():

  1. Guardar alguna constante con un valor distinto al cero; por ejemplo 17, en una variable int llamada result.
  2. Para cada campo significativo f en el objeto (es decir, cada campo que se tiene en cuenta al ejecutar un equals()), hacer lo siguiente:
    1. Calcular un int de hashCode para el campo:
      1. Si esl campo es un booleano, calcular c = (f ? 1 : 0)
      2. Si el campo es un byte, char, short o int, calcular c = (int) f
      3. Si el campo es un long, calcular c = (int) (f ^ (f >>> 32))
      4. Si el campo es un float, calcular c = Float.floatToIntBits(f)
      5. Si el campo es un double, calcular long l = Double.doubleToLongBits(f); c = (int) (l ^ (l >>> 32));
      6. Si el campo es una referencia a un objeto, calcular c = f.hashCode()
      7. Si el campo es un array, tratar a cada elemento por separado. Es decir, calcular el hashCode de cada elemento significativo usando las reglas anteriores.
    2. Combinar el hashCode calculado c en el paso 2.1 en un resultado como sigue: result = 37 * result + c;
  3. Retornar result
  4. Mirar al hashCode() resultante y asegurarse que instancias iguales tengan el mismo hashCode.

Veamos un ejemplo de este algoritmo:


public class HashTest {
private String campo1;
private short campo2;

//resto de la clase...

@Override
public int hashCode() {
int result = 17;
result = 37*result + campo1.hashCode();
result = 37*result + (int)campo2;
return result;
}
}

Como vemos elegimos la constante 37. La idea es ejegir un número que sea un número primo. Podemos elegir cualquier número primo. Al usar un número primo los objetos se distribuirán mejor en los baldes. Pueden aprender más sobre este algoritmo y la distribución que genera buscando en Internet.

Apache HashCodeBuilder

Como estamos aprendiendo, no es siempre facil retornar un buen valor de hashCode. Por suerte existen clases que nos pueden ayudar.

El paquete org.apache.commons.lang.builder de Jakarta-Commons contiene la clase HashCodeBuilder que está diseñada para ayudarnos a implementar el método hashCode(). Muchos desarrolladores luchan por escribir sus hashCode cuando existe esta clase que nos simplifica el proceso.

Así es como quedaría la clase de prueba anterior usando la clase HashCodeBuilder:


public class HashTest {
private String campo1;
private short campo2;

//resto de la clase...

@Override
public int hashCode() {
return new HashCodeBuilder(83, 7)
.append(campo1)
.append(campo2)
.toHashCode();
}
}

Noten que los dos números del constructor del HashCodeBuilder son dos números impares distintos a cero - estos números ayuda a evitar la colisión de valores de hashCode en otros objetos.

Si se necesita, se puede invocar al hashCode() de la superclase usando appendSuper(int).

Resulta muy facil escribir el método hashCode() usando la clase Apache HashCodeBuilder.

Objetos mutables como clave

Como consejo general, deberíamos usar objetos inmutables como clave en una colección. El hashCode funciona mejor cuando se calcula con datos inmutables. Si usamos objetos mutables como clave y estos objetos cambian su estado de manera que el hashcode también cambia, entonces el objeto almacenado quedará ubicado en un balde incorrecto dentro de la colección.

La cosa más importante a consdierar cuando se implementa el hashCode() es que, sin importar cuándo se invoca a este método, tiene que producir el mismo valor para un objeto en particular cada vez que se invoca. Si tenemos un escenario en donde el objeto produce un valor de hashCode() cuando se invoca al put() del HashMap y luego produce otro valor durante un get(), en ese caso no podremos recuperar este objeto. Por lo tanto, si nuestro hashCode() depende de datos mutables en el objeto, cambiar estos datos con seguridad producirán una nueva clave al generar un hashCode() diferente.

Veamos el siguiente ejemplo:


public class Empleado {

private String nombre;
private int edad;

public Empleado() {
}

public Empleado(String nombre, int edad) {
this.nombre = nombre;
this.edad = edad;
}

public String getNombre() {
return nombre;
}

public void setNombre(String nombre) {
this.nombre= nombre;
}

public int getEdad() {
return edad;
}

public void setEdad(int edad) {
this.edad = edad;
}

@Override
public boolean equals(Object obj) {
if (obj instanceof Empleado) {
Empleado emp = (Empleado)obj;
return (emp.nombre.equals(nombre) && emp.edad == edad);
}
return false;
}

@Override
public int hashCode() {
return nombre.length() + edad;
}

public static void main(String[] args) {
Empleado e = new Empleado("muhammad", 24);
Map map = new HashMap();
map.put(e, "Muhammad Ali Khojaye");

// encuentra el resultado
System.out.println(map.get(e));

e.nombre = "abid";

// el map devolverá null porque no lo encuentra
System.out.println(map.get(e));

// otra vez devolverá null
System.out.println(map.get(new Empleado("muhammad", 24)));
}
}

Vemos en el ejemplo anterior que obtenemos algunos resultados extraños. Después de cambiar el campo nombre, el cálculo del hashCode() devuelve un nuevo número y apuntará a un nuevo balde, por lo que el contains() devolverá false.

Podemos arreglar esta situación usando alguna de estas alternativas:

  • El hashcode es mejor calcularlo con datos inmutables; por lo tanto, asegurarnos que sólo usaremos objetos inmutables como claves de una colección.
  • Implementar el hashCode() usando la primer técnica: devolver un valor constante. En este caso tenemos que ser conscientes que estamos quitando todas las ventajas del mecanismo de baldes de las colecciones.
  • Si necesitamos incluiir campos mutables en el método de hashCode(), entonces podemos calcular y almacenar el valor del hash cuando se crea el objeto, y cada vez que se actualiza alguno de los campos mutables, primero debemos quitarlo de la colección y luego agregarlo nuevamente una vez hecho el cambio.
Traducido de Java Hashing, publicado en DZone.

miércoles, noviembre 04, 2009

awk continúa pateando traseros

En comp.programming alguién envió un interesante programa de perl para imprimir sólo la primera aparición de cada línea (o sea, eliminar líneas repetidas) de un archivo preservando el orden de las mismas (o sea, no teniendo que ordenar el archivo previamente).

Recordemos que la mayoría de las veces esta tarea se realiza con el comando de Unix "uniq", que requiere que se ordene el archivo previamente con el comando "sort".

La línea es:

perl -ne 'print $_ unless $seen{$_}++'

Muy bueno. Sin embargo alguién respondió con la siguiente línea de awk:

awk '!o[$0]++'

¡¡¡IN-CRE-í-BLE!!!

lunes, noviembre 02, 2009

Gadgets en abowman.com

El programador Adam Bowman ofrece gadgets muy locos para decorar blogs, entre otras cosas, en este sitio.

jueves, octubre 29, 2009

Tcl/Tk, un lenguaje con actitud de rock

Sin dudas el más grande invento desde los pañales descartables. Tcl/Tk es un lenguaje interpretado 100% libre creado por el profesor John K. Ousterhout en la universidad de California, que permite escribir scripts y programas de mayor complejidad con interfaces gráficas, sockets, bases de datos y decenas de extensiones para hacer de todo muy fácilmente.

Tcl/Tk se encuentra disponible para casi todas las plataformas, desde Linux hasta Windorch, pasando por Mac. Para programar en Tcl/Tk no hace falta ninguna herramienta especial, ni IDE. Sólo crear un archivo de texto nuevo, escribir nuestro código, y listo, si tenemos instalado el interprete ya se puede ejecutar.

Probablemente hay muchas razones por las que Tcl/Tk es popular, pero quiero nombrar algunas de las que dice en el propio sitio:
  1. Desarrollo Rápido: la razón más importante por la cual la gente usa Tcl es que consigue realizar su trabajo más rápido. En muchos casos, usted puede implementar aplicaciones 5-10x más rápido con Tcl que con otros lenguajes, especialmente si la aplicación utiliza interfaces gráficas, manejo de "strings", estructuras dinámicas de datos, sockets o requiere integración.
  2. Interfaces Gráficas: con Tk, Tcl ofrece facilidades para la creación de interfaces gráficas que son increíblemente simples pero muy potentes.
  3. Multiplataforma: Tcl/Tk se ejecuta en Windows, Macintosh, y casi todas las plataformas Unix que se pueda imaginar. Proporciona API de alto nivel que le permite escribir código que funciona de la misma - en todas partes -, mientras que en Tcl/Tk se preocupa por respetar las diferencias de plataforma, como el aspecto y comportamiento nativo para el GUI.
  4. Fácil de aprender: Tcl es un lenguaje muy simple. Los programadores experimentados pueden aprender Tcl y producir su primera aplicación interesante en tan sólo unas pocas horas o días. Los programadores casuales también puede aprender Tcl rápidamente.
  5. Madurez: Tcl/Tk ha estado bajo continuo y activo desarrollo y uso por un gran grupo de expertos desde la década de 1990.
  6. Deploy o Despliegue: los lenguajes dinámicos a menudo hacen más difícil la implementación, porque usted necesita obtener tanto el intérprete del lenguaje, las bibliotecas y la aplicación en cada máquina donde se ejecutará. Tcl/Tk ofrece soluciones muy interesantes para empaquetar todo esto en un único archivo ejecutable de poco más de 1MB.
  7. Abundancia de bibliotecas: decenas de bibliotecas maduras, para hacer muchas cosas.
  8. La comunidad: otra de las razones atractivas para el uso de Tcl es la gran comunidad de usuarios y desarrolladores que posee. La wiki es una fuente inagotable de recursos. También cuenta con un numeroso y solidario grupo de hackers, comp.lang.tcl, al que se puede recurrir cuando uno no encuentra soluciones.
  9. ¡Es Software Libre!
Como contra podría mencionar que hay muy pocos recursos en español, por lo que exige que conozcamos inglés básico.

Para mostrar la eficacia del lenguaje, copio de la wiki esta calculadora:


y el código de menos de 50 líneas:


¿Por dónde comenzar?

En la wiki hay varios recursos y enlaces a tutoriales. Me pareció que http://www.bin-co.com/tcl/tutorial/contents.php estaba más o menos bien. Aunque es en inglés, casi no se encuentran recursos en español para este lenguaje.

¿Dónde consigo Tcl/Tk?

Si está usando GNU/Linux, probablemente esté instalado o se encuentra en el repositorio de su distribución. Si está usando windorch, puede descargar ActiveTcl.

En este sitio he publicado un par de programitas hechos en Tcl/Tk, por lo que se pueden ver las entradas marcadas con dicha etiqueta.

martes, octubre 27, 2009

Los lenguajes más populares

El sitio http://langpop.com/ recopila datos acerca de los lenguajes de programación más populares.

sábado, octubre 24, 2009

Presentación de Log4j

Construye tu propia tira cómica online

Fuente: Oloblogger

Seguro que alguna vez hemos dejado de publicar un buen chiste que se nos pasó por la cabeza, simplemente porque no somos muy mañosos para el dibujo.

Esto se ha acabado porque hay muchas páginas que ofrecen herramientas para crear tu propia tira, así que el que no lo haga a partir de ahora es porque no le da la gana.

Monkey Dyne nos ofrece una forma muy sencilla de combinar personajes y texto. Aunque muy limitado, para diálogos de dos personajes resulta suficiente. Estos ya están diseñados y sólo hay que elegir cual ponemos a la izquierda y cual a la derecha. Admite hasta un bocadillo por personaje para cada una de las tres viñetas posibles.


En Witty Comics ya tenemos 48 personajes distintos y 60 fondos para elegir. Posibilidad de cambiar el bocadillo según sea un texto normal, pensamiento, grito o susurro. Personajes dibujados tipo años 70 y otros basados en animales. Previsualización directa.


Strip Generator tiene unos personajes mezcla de la Familia Adams y las Supernenas, pero permite mayor flexibilidad a la hora de crear y colocar los personajes. Con un catálogo aceptable de personajes, objetos y bocadillos, también permite cambiar los tamaños, rotar y la superposición de elementos.


Pixton tiene personajes muy simples prediseñados, que podemos personalizar algo más que en los anteriores casos: tamaño, cabello, color... e incluso cambiar la postura. La escena también es modificable y se pueden añadir objetos.

MakeBeliefsComix. Prácticamente todos los elementos son personalizables. Algo más flexible en cuanto al número de viñetas porque se puede elegir entre 2 y 4. Quince personajes a elegir con variaciones en cuanto a posición y expresión. También incluye la posibilidad de rotar, cambiar tamaño y posicionar libremente.


Pikistrips, aporta una variante que es la de subir las imágenes que quieras. Prácticamente me ha parecido un laboratorio de fotomontaje, pero adaptado al comic. Un montón de parámetros personalizables similares a los de los programas de edición de imágenes, bastantes modelos predefinidos de maquetado de viñetas y los bocadillos, que no podían faltar.

Bitstrips es el más completito, pero en consecuencia, el más complicado. Creo que no es recomendable para un trabajo esporádico, pero es el mejor si vas a hacer tiras con cierta frecuencia. Permite personalizar todos los rasgos de los personajes, así como su complexión, postura o vestimenta. Aunque tienes suficientes prediseñados para poder empezar, puedes crear tus propios personajes y guardarlos en tu librería personal. Muchos fondos, muchos objetos, muchos formatos de tira.

En casi todos los procesos de creación se dispone de un editor básico y de otro avanzado para poder recrearse un poco más.


sábado, octubre 17, 2009

La tabla periódica de las fuentes