miércoles, 4 de noviembre de 2009

Templates y Generics

Programación genérica

La programación genérica se basa en el uso de tipos paramétricos. Esto se consigue diciendo cosas como "una lista de enteros" o "una lista de cadenas". De forma usual esto se escribe

list<int>

list<string>

Generics

Ahora bien, el significado de estos tipos puede ser distinto. En Java (y en parte en C#) lo que se hace es borrar el tipo y usar el tipo objeto.

list<int> ----> list<object>

list<string> -----> list<object>

A cambio, el compilador comprueba los tipos e introduce las conversiones convenientes en cada caso. De esta forma hay seguridad en el uso de los tipos aunque realmente estemos trabajando sobre objetos genéricos. De ahí el nombre de estos tipos: tipos genéricos (generics).

Templates

En C++ los tipos no se borran, lo que se hace es generar un tipo nuevo a partir de un patrón. Así una lista de algo no es un tipo completo en C++ es un patrón. De ahí el nombre: patrones (templates).

list<X> ----> class { void insert(X x) {..} ..}

list<int> ----> class { void insert(int x) {..} ..}

list<string> ----> class { void insert(string x) {..} ..}

Obviamente esto es mucho más pesado para el compilador que requiere crear estos tipos. Por esta razón las compilaciones de C++ son mucho más largas que las de C# o las de Java. Realmente son macros que expanden el código a compilar.

Comparativa

Esta diferencia hace que existan casos no intuitivos. Por ejemplo, en Fabulous Adventures In Coding Eric Lippert nos muestra el siguiente ejemplo en C#.

public class C

{

public static void DoIt<T>(T t) {ReallyDoIt(t);}

private static void ReallyDoIt(string s)

  {System.Console.WriteLine("string");}

private static void ReallyDoIt<T>(T t)

  {System.Console.WriteLine("everything else");}

}

Si llamamos a C.DoIt<string> el compilador de C# borra el tipo (generics, no templates) y cuando llama a ReallyDoIt(t) es un object por lo que el resultado es "everything else".


0 comentarios:

Publicar un comentario en la entrada