El lenguaje de programacion D

En este artículo se hará una introducción al lenguaje de programación D para lo cual se explicarán las principales diferencias con respecto a C y C++; por ello sería aconsejable que el lector de este pequeño artículo conozca las características dichos lenguajes (u otros similares, como Java o C#) y algunos conceptos como la programación orientada a objetos o el control de errores mediante excepciones aunque no es necesario que sea un experto en dichos temas.

Este artículo no es un manual ni un tutorial y por lo tanto no es la mejor referencia para aprender el lenguaje, aunque alguien que conozca C++ o de Java podrá tener una idea muy completa de D tras leerlo.

En mi opinión, D es un lenguaje con un potencial increible, capaz de proporcionar al desarrollador la productividad y la elegancia de Python o Ruby pero con la eficiencia de C.

Este documento no está terminado y se irá ampliando con el tiempo; puede verse una lista de las cuestiones pendientes al final del mismo. La versión actual es la: 0.3 actualizada el 18 de septiembre de 2008. El documento es básicamente un resumen de la documentación de D, traducido, y por lo tanto la mayoría de los ejemplos están tomados de la misma. Aconsejo al lector interesado en el lenguaje que tras leer el artículo y haberse hecho una idea general, lea la referencia completa en digitalmars.com/d.

Cambios al artículo:

  • 18 de septiembre: ampliada la sección de cadenas, creada sección de propiedades (diatriba incluida), creada sección de guardas de ámbito. Arreglado "bug" en el ejemplo de los delegados (gracias Miguel.)

¿Qué tipo de lenguaje es D?

La clasificación del lenguaje de programación D sería: lenguaje compilado a código nativo (con compilación opcional a .NET como C#), orientado a objetos pero permitiendo programar con funciones libres y clases ligeras (structs), con plantillas y mixins (que permiten la programación genérica) y con posibilidad de acceso a bajo nivel.

¿Qué diferencias tiene con respecto a C++?

Esta clasificación parece exactamente la misma que la de C++ y no es casual, pues C++ es el lenguaje al que D aspira a sustituir. D es un lenguaje evolucionario, no revolucionario y en un principio puede parecer que no aporta demasiado sobre C++. Pero no son las características generales sino los detalles de las mismas los que marcan la diferencia. En primer lugar D conserva todas las características de expresividad de C++ (cosa que ni C# ni mucho menos Java consiguen en su afán por hacerse lenguajes más accesibles), pero con una sintaxis y unas construcciones mucho más sencillas y lógicas. Además, otro de los puntos fuertes de C++, su rendimiento, también se ve reflejado en D (en algunas ocasiones incluso superado.)

Por otro lado D cuenta con muchas otra características de las que C++ no dispone, de las cuales vamos a hacer un pequeño repaso a continuación. Quisiera recordar al lector que, al contrario de lo que pasa con Java o C#, estas características no suponen una perdida apreciable de rendimiento para D en comparación con C++:

Gestión automática de memoria (recolección de basura)

En C++ cuando creamos objetos que queremos que transciendan el ámbito de la función, método o bloque de código que los ha creado los creamos con utilizando el operador “new”. Este operador se encargará de asignar automáticamente la memoria que sea necesaria para el objeto y llamará a su constructor, devolviéndonos una referencia al objeto ya inicializado que podremos almacenar en una variable del tipo del objeto.

Cuando ya no vamos a necesitar el objeto procedemos a borrarlo con el operador “delete” lo que liberará la memoria asignada por el objeto. ¿Parece sencillo verdad? Bien, debería serlo, pero en la práctica es raro el programa en C++ que no tiene o ha tenido una fuga de memoria porque el flujo de ejecución de una parte del mismo termina antes de llegar al delete (y por lo tanto la memoria queda asignada para siempre sin posibilidad de recuperarla) o que ha fallado porque erróneamente se ha hecho un delete del mismo objeto dos veces o se ha intentado acceder (también erróneamente) a un miembro de un objeto previamente borrado. Obviamente estos errores son evitables pero errar es humano y cuantas más tareas delegue en el programador el lenguaje de programación más posibilidad hay de que haya errores (si no fuera así, todos seguiríamos haciendo ensamblador.)

La gestión automática de memoria quiere decir que el programador seguirá creando los nuevos objetos con "new" pero ya no tendrá que preocuparse de borrarlos con "delete" porque existirá un "recolector de basura" que se encargará de eliminar automáticamente los objetos para los que ya no exista ninguna referencia. Es decir, si tenemos la siguiente función:

void pierdeaceite() {
    Obj *o = new Obj();
}

En C++ esto produciría una fuga de memoria cada vez que la llamáramos porque al terminar la función ya no habría ninguna referencia a "o" (y por lo tanto no podríamos usarlo) y sin embargo al no haber hecho delete seguiría existiendo en la memoria. El código equivalente en D:

void nopierdeaceite() {
    Obj o = new Obj();
}

No produciría ninguna perdida de memoria porque el recolector de basura detectaría que como “o” fue declarado dentro de “nopierdeaceite” y su alcance termina al terminar la función, la memoria puede ser liberada.

Esta característica (con la que cuentan también C# y Java) puede desactivarse si por cuestiones de rendimiento o de cualquier otro tipo no queremos que se ejecute el recolector de basura llamando a gc.