D (lenguaje de programación)

D
Información sobre la plantilla
Parte de la familia Lenguaje de programación.
Dlp.png
Multiparadigma. Orientado a Objetos. Imperativo. Funcional y Meta.
DesarrolladorAndrei Alexandrescu y Walter Bright
Diseñado porWalter Bright y Andrei Alexandrescu
Última versión estable2.064

D es un lenguaje de programación de uso general desarrollado por Walter Bright y Andrei Alexandrescu cuya primera versión apareció en 1999. Se origina como un rediseño de C++, con un enfoque más pragmático, pero no es un lenguaje puramente derivado del anterior. D ha mantenido algunas características de C++ y también está influido por otros conceptos de otros lenguajes como Java, C# y Eiffel. Una versión estable fue lanzada el 2 de enero de 2007 y la ultima el 2 de agosto de 2012.

Clasificació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. 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.

Principales diferencias 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 otras características de las que C++ no dispone.

Características de las que C no dispone

  • 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. 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 ha fallado porque erróneamente se ha hecho un delete del mismo objeto dos veces 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. 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.

  • Gestión de errores mediante manejo de excepciones: C++ permite gestionar los errores mediante el mecanismo de manejo de excepciones, aunque por herencia de C en demasiadas ocasiones se sigue utilizando el sistema de "valores mágicos devueltos por la función".

En D el sistema de manejo de excepciones es superior al de C++ al incorporar algunas características de lenguajes más recientes. Cuando una excepción producida en código D no se captura, se muestra un mensaje de error con información de la excepción. La sintaxis es parecida a la de otros lenguajes con manejo de excepciones.

  • Guardas de ámbito para asegurar la ejecución de código a la salida de un ámbito: Aunque D tenga recolección automática de memoria hay otro tipo de recursos que se siguen teniendo que liberar manualmente. Ejemplos de estos recursos son los ficheros, los cerrojos y mutex; pero hay otros. Realmente, usando las guardas de ámbito, la instrucción finally nunca es necesaria aunque se sigue manteniendo en el lenguaje. Las guardas de inclusión no sustituyen a la instrucción except; para capturar excepciones y realizar operaciones en la captura debemos seguir usándola.

La guarda de ámbito de éxito (sucess) sería equivalente a el "else" de las excepciones en Python.

  • Estructuración del código en módulos y paquetes: En C/C++ la estructuración del código se hace creando "ficheros de cabecera" con extensión .h o .hpp que contienen las declaraciones de los símbolos que cada subparte explota, y luego esos ficheros de cabecera se importan usando la directiva del preprocesador #include. Esta importación lo único que hace es incluir el código del .h importado allí donde se encuentra la directiva import. Esto lleva a problemas cuando varios ficheros de cabecera definen un mismo símbolo, con soluciones poco elegantes. C++ añade además el concepto de namespaces que permite agrupar los símbolos de distintos ficheros en un único espacio de nombres lógico.

En D, como en casi todos los lenguajes modernos, la estructuración del código y las bibliotecas se hace usando módulos y paquetes. Un módulo no es más que un fichero fuente de código D (generalmente con extensión .d). Al contrario de lo que sucede en otros lenguajes, cuando importamos los símbolos de un módulo no hace falta anteponer el nombre del módulo con un punto antes de llamar a un símbolo.

  • Compatiblidad de llamada con C: Debido a la difusión del lenguaje, la mayoría de las APIs de sistemas operativos y librerías de sistemas están escritas en C u ofrecen una interfaz para el mismo. D puede acceder a bibliotecas de C. Para ello, además de enlazar con el fichero binario de la biblioteca mediante parámetros al compilador, debemos incluir en nuestro código D una declaración de los símbolos y funciones de C a los que queramos acceder. Como los tipos de datos de D suelen tener una correspondencia muy directa con los de C este proceso suele ser bastante sencillo; sin embargo para conversiones de ficheros de cabecera .h más complicados se dispone de la herramienta htod que realiza la conversión de tipos y sintaxis de forma automática, tomando como entrada un fichero .h de C y generando un fichero .d que podemos incluir en nuestros proyectos.
  • Delegados, funciones anidadas y funciones literales: En D existe un tipo de dato llamado "delegado" que puede usarse para pasar referencias a un método de una clase como parámetros para otras funciones y métodos. Son, en concepto, similares a los punteros a método de C++ pero con una sintaxis tanto de declaración como de creación y uso mucho más sencilla.

D permite tener funciones anidadas y funciones anónimas. Las primeras son funciones que están definidas dentro de otra función. Son muy útiles para estructurar nuestro código de una forma más jerárquica. Las funciones anónimas son funciones (normalmente sencillas) sin nombre que suelen utilizarse como argumento para una función que espera recibir una función como argumento.

  • Declaración anticipada de funciones innecesaria: En C y C++ para que una función pueda llamar a otra esta debe haber sido declarada con anterioridad a la misma. Para ello puede estar el cuerpo completo de la función, o sólo un "prototipo" que indica los tipos aceptados y el valor devuelto.

Otras Características

D está siendo diseñado con lecciones aprendidas del uso de C++ en vez de ser diseñado desde una perspectiva teórica. Aunque usa muchos de los conceptos de C/C++ también descarta algunos, y por lo tanto no es compatible con código escrito en C o C++. D retiene la habilidad de C++ de hacer código de bajo nivel, permitiendo incluir código en ensamblador. La herencia múltiple de C++ es reemplazada por herencia simple e interfaces y 'mixins'. La sintaxis de declaración y la sintaxis para las expresiones se parecen a las de C++.

El soporte del lenguaje ensamblador demuestra una de las diferencias entre D con respecto a otros lenguajes como Java y C#. Esto permite incluir código específico de la máquina con código D, una técnica comúnmente usada por programadores de software de sistema para acceder a características de bajo nivel necesarias para interactuar directamente con el hardware, permitiendo escribir software como sistemas operativos y drivers. D incluye soporte para comentarios de documentación, pero hasta ahora sólo el compilador entregado por Digital Mars implementa un generador de documentación.

Orientada a objetos

La programación orientada a objetos está basada en herencia simple, con todas las clases derivadas de la clase Object. D no soporta herencia múltiple; en vez de eso, usa interfaces parecidas a las de Java, que son comparables a las clases abstractas de C++.

Metaprogramación

Es soportada por una combinación de plantillas, ejecución de funciones en tiempo de compilación, tuplas y 'mixins' de cadena. Soporta CTFE (evaluación de funciones en tiempo de compilación).

Manejo de memoria

La memoria es usualmente manejada por un recolector de basura, pero objetos específicos pueden ser finalizados inmediatamente cuando salen del ámbito. Es posible el manejo de memoria explícito usando los operadores sobrecargados new y delete, y simplemente llamando las funciones malloc y free de C directamente. La recolección de basura puede ser controlada: los programadores pueden agregar y excluir rangos de memoria de ser observados por el recolector, pueden pausar y reanudar el recolector y forzar un ciclo generacional o de recolección completa. El manual da muchos ejemplos de cómo implementar diferentes esquemas de manejo de memoria altamente optimizados para cuando la recolección de basura es inadecuada para el programa.

Interacción con otros sistemas

La API de C es admitida, al igual que todos los tipos fundamentales y derivados de C, permitiendo acceso directo al código existente escrito en C y bibliotecas. La biblioteca estándar de C es parte del D estándar. A menos que se usen namespaces muy explícitos puede ser de alguna forma difícil de acceder, como se puede observar en módulos escritos en D que hagan uso de dicha característica. Pero la biblioteca estándar de D es usualmente suficiente.

Implementación

Las implementaciones actuales de D compilan el código directamente a código máquina para lograr una ejecución eficiente. Cambios al lenguaje no se hacen regularmente desde la versión 1.0. El diseño está virtualmente congelado, y nuevos lanzamientos se concentran en resolver bugs existentes. El compilador oficial de Walter Bright define el lenguaje.

  • DMD: El compilador de Digital Mars, el compilador oficial de D. El front end está bajo la licencia Artistic License y la licencia GNU GPL; las fuentes para el front end son distribuidas con los binarios del compilador. El back end es propietario, pero el código es abierto.
  • GDC: Un front end para el back end GCC, construido usando las fuentes del compilador *DMD. Snapshots soportan la versión 2.0 del lenguaje.
  • LDC: Un compilador basado en DMD y usa LLVM como back end. El backend LLVM permite que LDC logre optimizar el código alcanzando rendimiento similar a C/C++ e incluso superándolo en ocasiones.

Herramientas de desarrollo

D todavía no está soportado en muchos entornos de desarrollo, lo cual es un problema esencial para muchos usuarios. Editores que pueden ser usados incluyen a Entice Designer, emacs, vim, SciTE y Zeus entre otros. Vim soporta el resaltado de sintaxis y completado de código (a través de ctags parcheados). Code::Blocks incluye soporte parcial del lenguaje. Hay dos plu-gins en desarrollo para Eclipse, Descent y Mmrnmhrm. Adicionalmente, hay IDEs escritas en el propio D como Poseidon, que incluye completado de código, resaltado de sintaxis y depurador.

Aplicaciones escritas en D pueden ser depuradas con cualquier depurador de C o C++, como GDB o WinDbg, aunque soporte para varias características fundamentales de D es limitado. Un depurador con soporte explícito para D es Ddbg para Windows. El depurador comercial ZeroBUGS para Linux tiene soporte experimental para D. Ddbg puede ser usado con varios IDEs o desde la línea de comandos, ZeroBUGS tiene su propia interfaz gráfica.

Dificultades presentes en D

Sobrecarga de operadores

La sobrecarga de operadores en D a veces son menos poderosas que las de C++. Un ejemplo es el opIndex, que sufre porque D no permite regresar referencias. Esto hace operaciones como obj[i]++;imposibles. La solución parcial de D es el operador opIndexAssign, que solo repara casos donde la expresión indexeada es solo un valor L como obj[i] = 5 pero no los casos originales.

División en la biblioteca estándar

La biblioteca estándar en D es llamada Phobos. Algunos miembros de la comunidad piensan que Phobos es demasiado simple y que posee numerosos problemas, por lo cual un reemplazo llamado Tango fue escrito. Sin embargo, Tango y Phobos eran incompatibles debido a varias diferencias (soporte de hilos, recolector de basura, etc). La existencia de dos bibliotecas, ambas de uso elevado, llevó a problemas significativos donde algunos paquetes usan Phobos y otros usan Tango. Este problema fue resuelto con la versión 2.0 del lenguaje.

Soporte sin finalizar para bibliotecas compartidas/dinámicas

Bibliotecas compartidas ELF de Unix son soportadas hasta un punto usando el compilador GDC. En Windows, DLLs son soportadas y permiten a objetos recolectados por el recolector de basura de ser seguramente pasados a funciones de C, ya que el recolector de basura revisa el stack por punteros. Sin embargo, todavía hay limitaciones con DLLs en D incluyendo el hecho de que la información en tiempo de ejecución de clases definidas en la DLL es incompatible con esas definidas en el ejecutable, y que cualquier objeto creado desde la DLL debe ser finalizado antes de que la DLL sea descargada.

Referencias

Fuentes

  • The D Programming Language, Addison-Wesley Professional
  • D Programming Language 1.0. Digital Mars