miércoles, 10 de noviembre de 2010

Compilación de ejecutable con Qt Creator

Cuando creamos una aplicación con Qt Creator en Windows es necesario incluir los ficheros dll de Qt para que la aplicación funcione correctamente.

En ocasiones este no es el comportamiento deseado, se puede generar un fichero ejecutable autónomo (sin necesidad de ninguna librería dll externa) ejecutando el siguiente comando:

qmake -nodepend -o Makefile project.pro

Si no se encuentra el programa qmake hay que añadirlo al PATH, la instalación por defecto de QT Creator no lo hace.
Una vez ejecutado el comando anterior, al compilar obtendremos un ejecutable con toda la funcionalidad incluida, sin necesidad de incluir ningún fichero dll.

domingo, 17 de octubre de 2010

Anidamiento de módulos en ruby

Tal y como ocurre en python con los decoradores, cuando se programa un módulo en ruby debería dejarse la puerta abierta a que no fuera el único.

En el siguiente ejemplo tenemos dos módulos (Printable y Serializable), ambos métodos se deben poder combinar en cualquier orden y pudiendo aparecer uno, ninguno o ambos.

La clave para que un mismo método se ejecute en la clase y en cada uno de sus módulos, es la llamada a super.

En otros lenguajes esto no sería correcto, puesto que los módulos Printable y Serializable no son superclase de la clase Test, pero en ruby, super no llama exactamente a la superclase, sino que repite el mismo método que se está ejecutando obviando la definición actual.

module Printable
def print_method
super
puts "I'm printable"
end
end

module Serializable
def print_method
super
puts "I'm serializable"
end
end


class Test
include Printable
include Serializable

def method_missing(method, *args, &block)
super if method.to_s != 'print_method'
end

def print_method
super
puts "I'm object of Test class"
end

end

t = Test.new
t.print_method

Con este planteamiento hay un problema añadido, al final de la cadena de llamadas a print_method estará la clase de la que hereda Test, y esta clase no tiene porqué tener implementado print_method.

Para solucionarlo en este caso se redefine el method_missing, cuando llegue el momento de ejecutar el método en alguna clase/módulo que no lo entienda, se corta la cadena de ejecuciones.

I'm printable
I'm serializable
I'm object of Test class

viernes, 17 de septiembre de 2010

Conversión implícita de tipos

Es común escribir nuevas clases que expandan a las básicas del lenguaje.

Uno de los problemas que nos podemos encontrar cuando hacemos esto es la conversión de tipos.

Si por ejemplo creamos una nueva clase para manejar cadenas, el código se llenará rápidamente de castings para convertir las cadenas nativas del lenguaje a nuestra implementación. Esto ocurre sobre todo en lenguajes fuertemente tipados.

C# provee una solución bastante elegante, la conversión implícita de tipos.

Para mostrar el uso de esta característica se muestra una clase con dos tipos, una cadena y un entero y sus declaraciones de conversiones implícitas.

public class MyClass
{
private string str { get; set; }
private int number { get; set; }

public static implicit operator MyClass(string s)
{
MyClass ms = new MyClass();
ms.str = s;
return ms;
}

public static implicit operator MyClass(int i)
{
MyClass ms = new MyClass();
ms.number = i;
return ms;
}

public string getStr()
{
return str;
}

public int getNumber()
{
return number;
}
}

Declarando un operador estático, implícito y público se consigue la sintaxis siguiente para la conversión de tipos.

MyClass ms1 = "hello";
MyClass ms2 = 2;

Console.WriteLine(ms1.getStr());
Console.WriteLine(ms2.getNumber());

En el ejemplo se puede ver que no es necesaria ninguna conversión, y se pasan tanto la cadena "hello" como el entero 2 a tipo MyClass.

domingo, 12 de septiembre de 2010

Extension methods en c#

En algunos lenguajes dinámicos como ruby las clases se denominan "abiertas".
Esto significa que a cualquier clase se le puede añadir nuevos métodos o funcionalidades en tiempo de ejecución.

Los lenguajes fuertemente tipados no suelen ofrecer tanta libertad, pero se disponen de otras herramientas.

En C#, se pueden definir clases parciales, lo que significa que se puede definir el comportamiento de la clase en varias etapas.

public partial class PartialClass
{
public static void method1()
{
Console.WriteLine("method1");
}
}
...
public partial class PartialClass
{
public static void method2()
{
Console.WriteLine("method2");
}
}

Manteniendo las clases como parciales en cualquier momento se puede añadir funcionalidad a una clase existente fuera de su definición original.

Este método es útil tan solo para las clases que programamos, pero si queremos extender una librería externa o las clases del propio lenguaje las clases parciales no son de gran ayuda.

C# tiene en cambio una posibilidad más interesante, los "extension methods".

public static class ExtensionMethods
{
public static string withDot(this string str)
{
return str + ".";
}
}
...
string str = "text ";
str.withDot();

Con el código anterior se le añade a la clase string el nuevo método (withDot).
Para hacer lo mismo sin "extension methods" habría sido necesario crear una nueva clase que heredara de string y añadirle el método withDot.

Gracias a los "extension methods" se puede evitar crear clases intermedias para extender funcionalidades de las ya existentes.

sábado, 28 de agosto de 2010

Implementación explícita de interfaces en C#

Por diversas razones como la colisión de nombres o simplemente por diseño, puede que necesitemos mayor granularidad para distinguir que método de que interfaz estamos definiendo.

Supongamos que tenemos el caso de una clase que implementa dos interfaces tal y como sigue:

public interface IInterface1
{
int method();
int method1();
}

public interface IInterface2
{
int method();
int method2();
}

public class ExampleClass : IInterface1, IInterface2
{
public int method() { return 1; }
public int method1() { return 1; }
public int method2() { return 2; }

}

En este caso, el método method está presente en las dos interfaces y lo definimos en la clase.

Si necesitáramos distinguir alguno de los casos se podría usar la implementación explícita de interfaces.

public class ExampleClass : IInterface1, IInterface2
{
public int method() { return 1; }
public int method1() { return 1; }
public int method2() { return 2; }

int IInterface1.method() { return 1; }
int IInterface2.method() { return 2; }

}


public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();

ExampleClass example = new ExampleClass();
IInterface1 i1 = (IInterface1)example;
IInterface2 i2 = (IInterface2)example;

MessageBox.Show("Interface 1: " + i1.method());
MessageBox.Show("Interface 2: " + i2.method());
}
}

Esto devolvería como resultados 1 y 2 respectivamente. Como vemos, a pesar de realizar la implementación explícita de ambas interfaces se sigue pudiendo implementar de la forma tradicional como caso base.

miércoles, 21 de julio de 2010

Internacionalización con QT

La librería QT está desarrollada de tal forma que las aplicaciones
que estén hechas usando su API pueden internacionalizarse de forma bastante
fácil.

En primer lugar todas las cadenas de la aplicación deben sustituirse por llamadas
a la función tr.

QObject::tr("cadena");

La cadena que pasemos a la función tr servirá de índice para las cadenas
definitivas en los distintos idiomas.

Después se debe añadir una entrada en el fichero de proyecto (.pro) con los ficheros
que se deben generar para cada idioma de las traducciones, con extensión .ts.

TRANSLATIONS = en.ts es.ts

Los ficheros se generarán al ejecutar el comando:

lupdate proyecto.pro

Estos ficheros .ts se pueden editar con QT Linguist, una vez introducidas todas las
traducciones, se pueden exportar mediante la opción Release, esto generaráa
unos ficheros .qm.

Posteriormente hay que crear un fichero de recursos que contenga los ficheros .qm
de traducciones.

Para obtener el idioma del equipo en el que se está ejecutándo la aplicación se puede
hacer lo siguiente

QString locale = QLocale::system().name();

Para que las traducciones se carguen hay que instanciar la clase QTranslator y pasársela
a la aplicación.

QTranslator translator;
translator.load(locale, ":/");
a.installTranslator(&translator);

La ruta ":/" se refiere al prefijo introducido en el fichero de recursos.

Tras estos pasos las cadenas de la aplicación aparecerán traducidas dependiendo del idioma
del equipo en el que se esté ejecutándo.

jueves, 15 de julio de 2010

Como implementar interfaces en C++

C++ por si solo no trata las interfaces como un concepto diferenciado. Sin embargo se puede trabajar con interfaces tipo Java o C# aprovechándose de la heréncia múltiple creando clases abstractas.

En el siguiente ejemplo las clases ClassA y ClassB implementan la interfaz Interface, para ello tan solo tienen que redefinir el método method.

class Interface{
public:
virtual int method(int param) = 0;
virtual ~Interface(){};
};

class ClassA : public Interface{
public:
int method(int param){return param+1;}
};

class ClassB : public Interface{
public:
int method(int param){return param+2;}
};

Todos los usos que se le dan normalmente a las interfaces siguen siendo válidos con esta aproximación, con una salvedad, si queremos pasar la interfaz como parámetro a una función normalmente se haría como sigue.

std::string function(Interface i){
std::string str;

int number = i.method(1);
if(number==2){str = "ClassA";}
else if(number==3){str = "ClassB";}

return str;
}

Sin embargo, si hacemos esos el compilador protestará con un error similar a: "cannot declare parameter 'i' to be of abstract type 'interface'".

¿Por qué?
Esto ocurre porque por defecto en C++ los parámetros se pasan por valor, el objeto 'i' es imposible de crear ya que es de un tipo abstracto, el compilador no puede instanciarlo.

¿Qué solución hay?
Pasarlo como referencia, con una definición como la siguiente.

std::string function(Interface &i)

Si queremos asegurarnos que el parámetro no se modifica, habría que pasarlo como referencia constante.

std::string function(const Interface &i)

Esto plantea un nuevo problema, generando un error de compilación similar a: "passing 'const Interface' as 'this' argument of 'virtual int Interface::method(int)' discards qualifiers".

No se puede llamar a una función no constante desde un objeto constante. Para solucionarlo los métodos de la interfaz deberían ser constantes, quedando como sigue.

class Interface{
public:
virtual int method(int param) const = 0;
virtual ~Interface(){};
};

class ClassA : public Interface{
public:
int method(int param) const{return param+1;};
};

class ClassB : public Interface{
public:
int method(int param) const{return param+2;};
};