.. Introducción y breve reseña del lenguaje de programación D. También
se presentan las necesidades particulares de D con respecto al
recolector de basura y su estado actual.
- ESTADO: TERMINADO
+ ESTADO: TERMINADO, CORREGIDO
.. _d_lang:
----------------------------------------------------------------------------
D_ es un lenguaje de programación relativamente joven. Nació en 1999 y el
-2 de enero de 2007 salió su `versión 1.0`__. Poco tiempo después se
-continúo el desarrollo del lenguaje en la `versión 2.0`__, aún inestable
-y en la cual se está experimentando principalmente sobre
-multi-procesamiento.
+2 de enero de 2007 salió su `versión 1.0`__. Poco tiempo después se continúo
+el desarrollo del lenguaje en la `versión 2.0`__, aún inestable y en la cual
+se está experimentando principalmente sobre multi-procesamiento.
__ `D 1.0`_
__ `D 2.0`_
El lenguaje fue diseñado e implementado por `Walter Bright`_, desarrollador
-principal de Zortech C++, uno de los primeros compilador de C++ que
-compilaba a código nativo, y está fuertemente influenciado éste. Sin
-embargo toma muchos conceptos de otros lenguajes de más alto nivel, como
-Java_ o incluso lenguajes dinámicos como Perl_.
+principal de Zortech C++, uno de los primeros compilador de C++ que compilaba
+a código nativo, y está fuertemente influenciado éste. Sin embargo toma muchos
+conceptos de otros lenguajes de más alto nivel, como Java_ o incluso lenguajes
+dinámicos como Perl_.
El origen del lenguaje está plasmado en su sitio web, en donde se cita:
- It seems to me that most of the "new" programming languages fall into
- one of two categories: Those from academia with radical new paradigms
- and those from large corporations with a focus on RAD and the web. Maybe
- it's time for a new language born out of practical experience
- implementing compilers.
+ It seems to me that most of the "new" programming languages fall into one
+ of two categories: Those from academia with radical new paradigms and those
+ from large corporations with a focus on RAD and the web. Maybe it's time
+ for a new language born out of practical experience implementing compilers.
Esto podría traducirse como:
y web. Tal vez es hora de que nazca un nuevo lenguaje de la experiencia
práctica implementando compiladores.
-La versión 1.0 fue más bien una etiqueta arbitraria que un indicador real
-de estar ante una versión estable y completa. Luego de liberarse se
-siguieron agregando nuevas características al lenguaje hasta que se empezó
-el desarrollo en paralelo de la versión 2.0 al introducirse el concepto de
-inmutabilidad y funciones *puras* [#dpure]_ (a mediados de 2007).
+La versión 1.0 fue más bien una etiqueta arbitraria que un indicador real de
+estar ante una versión estable y completa. Luego de liberarse se siguieron
+agregando nuevas características al lenguaje hasta que se empezó el desarrollo
+en paralelo de la versión 2.0 al introducirse el concepto de inmutabilidad
+y funciones *puras* [#dpure]_ (a mediados de 2007).
.. [#dpure] Por funciones *puras* en D_ se entiende que no tienen efectos
- colaterales. Es decir, una función pura siempre que se llame con la
- misma entrada producirá el mismo resultado. Esto es análogo a como
- funcionan los lenguajes funcionales en general, abríendo la puerta a la
- programación de estilo funcional en
- D_.
+ colaterales. Es decir, una función pura siempre que se llame con la misma
+ entrada producirá el mismo resultado. Esto es análogo a como funcionan los
+ lenguajes funcionales en general, abríendo la puerta a la programación de
+ estilo funcional en D_.
A partir de este momento la versión 1.0 quedó *teóricamente* congelada,
-introduciendo solo cambios que arreglen errores (*bug fixes*),
-introduciendo todos las nuevas características solamente en la versión
-2.0 del lenguaje. La realidad es que se hicieron cambios incompatibles a la
-versión 1.0 del lenguaje en reiteradas ocasiones, pero se fue tendiendo
-a cada vez introducir menos cambios incompatibles. Sin embargo al día de
-hoy el compilador de referencia sigue teniendo algunas características
-presentes en la especificación del lenguaje sin implementar, por lo que
-todavía no hay una implementación completa de la versión 1.0 del lenguaje,
-siendo esta etiqueta todavía un poco arbitraria.
+introduciendo solo cambios que arreglen errores (*bug fixes*), introduciendo
+todos las nuevas características solamente en la versión 2.0 del lenguaje. La
+realidad es que se hicieron cambios incompatibles a la versión 1.0 del
+lenguaje en reiteradas ocasiones, pero se fue tendiendo a cada vez introducir
+menos cambios incompatibles. Sin embargo al día de hoy el compilador de
+referencia sigue teniendo algunas características presentes en la
+especificación del lenguaje sin implementar, por lo que todavía no hay una
+implementación completa de la versión 1.0 del lenguaje, siendo esta etiqueta
+todavía un poco arbitraria.
El lenguaje ha sido, hasta el desarrollo de la versión 2.0 al menos, un
esfuerzo unipersonal de `Walter Bright`_, dados sus problemas a la hora de
-delegar o aceptar contribuciones. Esto motivó a la comunidad de usuarios de
-D_ a crear bibliotecas base alternativas a la estándar (llamada Phobos_) en
-las cuales se pudiera trabajar sin las trabas impuestas por el autor del
-lenguaje.
+delegar o aceptar contribuciones. Esto motivó a la comunidad de usuarios de D_
+a crear bibliotecas base alternativas a la estándar (llamada Phobos_) en las
+cuales se pudiera trabajar sin las trabas impuestas por el autor del lenguaje.
En este contexto nacen primero Mango_ y luego Ares_. Mango_ fue creada por
Kris Macleod Bell a principios de 2004 como una biblioteca que provee
-servicios básicos de entrada/salida (o *I/O* de *input/output* en inglés)
-de alto rendimiento. Siendo estos servicios algo básico lo más natural
-hubiera sido que se encuentren en la biblioteca estándar de D_ pero por las
+servicios básicos de entrada/salida (o *I/O* de *input/output* en inglés) de
+alto rendimiento. Siendo estos servicios algo básico lo más natural hubiera
+sido que se encuentren en la biblioteca estándar de D_ pero por las
dificultades para contribuir a ésta, se desarrolla como una biblioteca
separada. A mediados de 2004 Sean Kelly crea Ares_ , con las mismas
-motivaciones pero con la intención de crear una biblioteca base (conocida
-en inglés como *runtime*) que incluye los servicios básicos que necesita el
+motivaciones pero con la intención de crear una biblioteca base (conocida en
+inglés como *runtime*) que incluye los servicios básicos que necesita el
lenguaje (información de tipos, manejo de excepciones e hilos, creación
y manipulación de objetos, recolector de basura, etc.). Al poco tiempo de
liberarse Ares_, Mango_ empieza a utilizarla como biblioteca base.
-Para comienzos de 2006, se empieza a trabajar en la combinación de
-ambas bibliotecas para lograr una biblioteca estándar alternativa
-con un alto grado de cohesión. Finalmente a principios de 2007,
-coincidiendo por casualidad con la aparición de D_ 1.0, se anuncia el
-resultado de este combinación bajo el nombre de Tango_, proveyendo una
-alternativa completa y madura a la biblioteca estándar de D_ Phobos_.
-A principios de 2008 los principales desarrolladores de Tango_ (Kris Bell,
-Sean Kelly, Lars Ivar Igesund y Michael Parker publican el libro llamado
-`Learn to Tango with D`_.
-
-Esto por un lado fue un gran avance porque dio un impulso muy considerable
-al lenguaje pero por otro un gran retroceso, porque todavía al día de hoy
-D_ 1.0 tiene 2 bibliotecas base, una estándar pero de peor calidad y menos
-mantenida y una alternativa de mayor calidad y apertura a la comunidad
-(pero no estándar). El peor problema es que ambas son **incompatibles**,
-por lo que un programa hecho con Tango_ no funciona con Phobos_ y viceversa
-(a menos que el programador haya invertido una cantidad de tiempo no
-trivial en asegurarse de que funcione con ambas).
+Para comienzos de 2006, se empieza a trabajar en la combinación de ambas
+bibliotecas para lograr una biblioteca estándar alternativa con un alto grado
+de cohesión. Finalmente a principios de 2007, coincidiendo por casualidad con
+la aparición de D_ 1.0, se anuncia el resultado de este combinación bajo el
+nombre de Tango_, proveyendo una alternativa completa y madura a la biblioteca
+estándar de D_ Phobos_. A principios de 2008 los principales desarrolladores
+de Tango_ (Kris Bell, Sean Kelly, Lars Ivar Igesund y Michael Parker publican
+el libro llamado `Learn to Tango with D`_.
+
+Esto por un lado fue un gran avance porque dio un impulso muy considerable al
+lenguaje pero por otro un gran retroceso, porque todavía al día de hoy D_ 1.0
+tiene 2 bibliotecas base, una estándar pero de peor calidad y menos mantenida
+y una alternativa de mayor calidad y apertura a la comunidad (pero no
+estándar). El peor problema es que ambas son **incompatibles**, por lo que un
+programa hecho con Tango_ no funciona con Phobos_ y viceversa (a menos que el
+programador haya invertido una cantidad de tiempo no trivial en asegurarse de
+que funcione con ambas).
Esto hace que la compatibilidad de programas y bibliotecas esté muy
-fragmentada entre las 2 bibliotecas base. Si bien no parece que vaya
-a haber solución alguna a este problema para D 1.0, D 2.0 va en camino
-a solucionar este problema ya que utiliza DRuntime_, un nuevo intento de
-Sean Kelly por proveer una biblioteca *runtime* bien organizada
-y mantenida, que es una adaptación de la biblioteca *runtime* de Tango_
-a D 2.0. Si bien todavía Tango_ no fue adaptada a D 2.0, se espera que
-cuando esto pase compartan la misma biblioteca *runtime* permitiendo que
-bibliotecas y programas hechos para Tango_ y Phobos_ 2.0 puedan coexistir
-sin problemas.
+fragmentada entre las 2 bibliotecas base. Si bien no parece que vaya a haber
+solución alguna a este problema para D 1.0, D 2.0 va en camino a solucionar
+este problema ya que utiliza DRuntime_, un nuevo intento de Sean Kelly por
+proveer una biblioteca *runtime* bien organizada y mantenida, que es una
+adaptación de la biblioteca *runtime* de Tango_ a D 2.0. Si bien todavía
+Tango_ no fue adaptada a D 2.0, se espera que cuando esto pase compartan la
+misma biblioteca *runtime* permitiendo que bibliotecas y programas hechos para
+Tango_ y Phobos_ 2.0 puedan coexistir sin problemas.
Descripción general
D_ es un lenguaje de programación con sintaxis tipo C, multi-paradigma,
compilado, con *tipado* fuerte y estático, buenas capacidades tanto de
programación de bajo nivel (*system programming*) como de alto nivel. Es
-compatible de forma binaria con C (se puede enlazar código objeto C con
-código objeto D). Con estas características, D_ logra llenar un vacío
-importante que hay entre lo lenguajes de alto bajo nivel y los de alto
-nivel [BKIP08]_. Si bien tiene herramientas de muy bajo nivel, que por lo
-tanto son muy propensas a errores, da una infinidad de mecanismos para
-evitar el uso de estas herramientas a menos que sea realmente necesario.
-Además pone mucho énfasis en la programación confiable, para lo cual provee
-muchos mecanismos para detectar errores en los programas de forma temprana.
-
-Si puede pensarse en C++ como un "mejor C", podría decirse que D_ es
-un "mejor C++", ya que el objetivo del lenguaje es muy similar a C++,
-pero implementa muchas características que jamás pudieron entrar en
-el estándar de C++ y lo hace de una forma mucho más limpia, ya que
-no debe lidiar con problemas de compatibilidad hacia atrás, y cuenta
-con la experiencia del camino recorrido por C++, pudiendo extraer de
-él los mejores conceptos pero evitando sus mayores problemas también.
+compatible de forma binaria con C (se puede enlazar código objeto C con código
+objeto D). Con estas características, D_ logra llenar un vacío importante que
+hay entre lo lenguajes de alto bajo nivel y los de alto nivel [BKIP08]_. Si
+bien tiene herramientas de muy bajo nivel, que por lo tanto son muy propensas
+a errores, da una infinidad de mecanismos para evitar el uso de estas
+herramientas a menos que sea realmente necesario. Además pone mucho énfasis
+en la programación confiable, para lo cual provee muchos mecanismos para
+detectar errores en los programas de forma temprana.
+
+Si puede pensarse en C++ como un "mejor C", podría decirse que D_ es un "mejor
+C++", ya que el objetivo del lenguaje es muy similar a C++, pero implementa
+muchas características que jamás pudieron entrar en el estándar de C++ y lo
+hace de una forma mucho más limpia, ya que no debe lidiar con problemas de
+compatibilidad hacia atrás, y cuenta con la experiencia del camino recorrido
+por C++, pudiendo extraer de él los mejores conceptos pero evitando sus
+mayores problemas también.
Otra gran diferencia con C++ es la facilidad para ser analizado
-gramaticalmente (*parsing*), ya fue especialmente diseñado para ser
-sencillo y a diferencia de C y C++ su gramática es independiente del
-contexto (*context-free grammar*). Esto permite que D pueda ser compilado
-en pequeños pasos bien separados:
+sintácticamente (*parsing*), ya fue especialmente diseñado para ser sencillo
+y a diferencia de C y C++ su gramática es independiente del contexto
+(*context-free grammar*). Esto permite que D pueda ser compilado en pequeños
+pasos bien separados:
1. Análisis léxico.
2. Análisis sintáctico.
4. Optimizaciones.
5. Generación de código.
-Esto favorece la creación de herramientas dada la facilidad de usar
-solamente la cantidad de análisis necesario para cada herramienta (por
-ejemplo un editor de textos puede tener hasta análisis sintáctico para
-proveer resaltado o un entorno de desarrollo puede proveer herramientas de
-re-factorización de código haciendo uso del análisis semántico).
+Esto favorece la creación de herramientas dada la facilidad de usar solamente
+la cantidad de análisis necesario para cada herramienta (por ejemplo un editor
+de textos puede tener hasta análisis sintáctico para proveer resaltado o un
+entorno de desarrollo puede proveer herramientas de re-factorización de código
+haciendo uso del análisis semántico).
-
-Una de las características que nunca pudo entrar en el estándar de C++
-es la recolección de basura. D_ no comete el mismo error.
+Una de las características que nunca pudo entrar en el estándar de C++ es la
+recolección de basura. D_ no comete el mismo error.
Características del lenguaje
----------------------------------------------------------------------------
-A continuación se enumeran las principales características de D_,
-agrupadas por unidades funcional o paradigmas que soporta:
+A continuación se enumeran las principales características de D_, agrupadas
+por unidades funcional o paradigmas que soporta:
La programación genérica se trata de la capacidad de poder desarrollar
algoritmos y estructuras independientes de los tipos que manipulan (pero de
forma segura o *type-safe*). Esto fue muy popularizado por C++ gracias a su
-soporte de plantillas (*templates*) y luego otros lenguajes como Java_
-y `C#`_ lo siguieron. Sin embargo otros lenguajes proveen formas más
-avanzadas de programación genérica, gracias a sistemas de tipos más
-complejos (como Haskell_).
-
-La meta-programación se refiere en general a la capacidad de un lenguaje
-para permitir generar código dentro del mismo programa de forma automática.
-Esto permite evitar duplicación de código y fue también muy popularizado
-por el soporte de *templates* de C++, aunque muchos otros lenguajes tienen
-mejor soporte de meta-programación, en especial los lenguajes dinámicos
-(como Python_).
+soporte de plantillas (*templates*) y luego otros lenguajes como Java_ y `C#`_
+lo siguieron. Sin embargo otros lenguajes proveen formas más avanzadas de
+programación genérica, gracias a sistemas de tipos más complejos (como
+Haskell_).
+
+La meta-programación se refiere en general a la capacidad de un lenguaje para
+permitir generar código dentro del mismo programa de forma automática. Esto
+permite evitar duplicación de código y fue también muy popularizado por el
+soporte de *templates* de C++, aunque muchos otros lenguajes tienen mejor
+soporte de meta-programación, en especial los lenguajes dinámicos (como
+Python_).
D_ provee las siguientes herramientas para realizar programación genérica
y meta-programación:
``if`` estático (``static if``):
- puede verse como similar a la directiva del preprocesador de C/C++
- ``#if``, pero a diferencia de esto, en D_ el ``static if`` tiene acceso
- a todos los símbolos del compilador (constantes, tipos, variables, etc).
+ puede verse como similar a la directiva del preprocesador de C/C++ ``#if``,
+ pero a diferencia de esto, en D_ el ``static if`` tiene acceso a todos los
+ símbolos del compilador (constantes, tipos, variables, etc).
Ejemplo::
Más información en http://www.digitalmars.com/d/1.0/version.html#staticif
Inferencia de tipos básica implícita y explícita (mediante ``typeof``):
- si no se especifica un tipo al declarar una variable, se infiere del
- tipo de su inicializador.
+ si no se especifica un tipo al declarar una variable, se infiere del tipo
+ de su valor de inicialización.
Ejemplo::
Más información en
http://www.digitalmars.com/d/1.0/declaration.html#AutoDeclaration
- Mediante el uso de ``typeof`` se puede solicitar el tipo de una
- expresión arbitraria.
+ Mediante el uso de ``typeof`` se puede solicitar el tipo de una expresión
+ arbitraria.
Ejemplo::
Iteración sobre colecciones (``foreach``):
cualquier tipo de colección (arreglos estáticos y dinámicos, arreglos
- asociativos, clases, estructuras o delegados) puede ser iterada mediante
- la sentencia ``foreach``.
+ asociativos, clases, estructuras o delegados) puede ser iterada mediante la
+ sentencia ``foreach``.
Ejemplo::
total += i;
*Templates*:
- clases y funciones pueden ser parametrizadas. Esto permite desarrollar
- algoritmos genéricos sin importar el tipo de los datos de entrada,
- siempre y cuando todos los tipos tengan una *interfaz* común. Esto
- también es conocido como *polimorfismo en tiempo de compilación*, y es
- la forma más básica de programación genérica.
+ clases y funciones pueden ser generalizadas. Esto permite desarrollar
+ algoritmos genéricos sin importar el tipo de los datos de entrada, siempre
+ y cuando todos los tipos tengan una *interfaz* común. Esto también es
+ conocido como *polimorfismo en tiempo de compilación*, y es la forma más
+ básica de programación genérica.
Ejemplo::
auto i = sumar!(int)(5, 6); // i == 11
auto f = sumar!(float)(5, 6); // j == 11.0f
- Además se pueden definir bloques de declaraciones parametrizados (esto
- no es posible en C++), permitiendo instanciar dicho bloque con
- parámetros particulares. Esto sirve como un mecanismo para la
- reutilización de código, ya que puede incluirse un mismo bloque en
- distintos lugares (por ejemplo clases). Un bloque parametrizado puede
- verse como una especie de módulo.
+ Además se pueden definir bloques de declaraciones generalizadas (esto no
+ es posible en C++), permitiendo instanciar dicho bloque con parámetros
+ particulares. Esto sirve como un mecanismo para la reutilización de código,
+ ya que puede incluirse un mismo bloque en distintos lugares (por ejemplo
+ clases). Un bloque generalizado puede verse como una especie de módulo.
Ejemplo::
bloque!(int, float).x = 5;
float f = bloque!(int, float).foo(7);
- La utilidad más prominente de los bloques parametrizados se da al
+ La utilidad más prominente de los bloques generalizados se da al
acompañarse de *mixins*.
-Instanciación implícita de funciones parametrizadas:
+Instanciación implícita de funciones generalizadas:
el lenguaje es capaz de deducir los parámetros siempre que no hayan
ambigüedades
auto f = sumar(5.0f, 6.0f); // f == 11.0f
Especialización explícita y parcial de *templates*:
- la especialización de *templates* consiste, al igual que en C++, en
- proveer una implementación especializada para un tipo de dato (o valor)
- de los parámetros. Especialización parcial se refiere a la capacidad
- de especializar un parámetro a través de un subtipo. Por ejemplo, se
- puede especializar un *template* para cualquier tipo de puntero, o para
- cualquier tipo de arreglo dinámico, sin necesidad de especificar el tipo
- al que apunta dicho puntero o el tipo almacenado por el arreglo.
+ la especialización de *templates* consiste, al igual que en C++, en proveer
+ una implementación especializada para un tipo de dato (o valor) de los
+ parámetros. Especialización parcial se refiere a la capacidad de
+ especializar un parámetro a través de un subtipo. Por ejemplo, se puede
+ especializar un *template* para cualquier tipo de puntero, o para cualquier
+ tipo de arreglo dinámico, sin necesidad de especificar el tipo al que
+ apunta dicho puntero o el tipo almacenado por el arreglo.
Ejemplo de especialización::
Tipos, valores (incluyendo *strings*) y *templates* como parámetros:
esto es otro bloque de construcción importantísimo para la programación
genérica en D, ya que combinando *templates* que toman *strings* como
- parámetro en combinación con *string mixins* pueden hacerse toda clase
- de meta-programas.
+ parámetro en combinación con *string mixins* pueden hacerse toda clase de
+ meta-programas.
Ejemplo::
string s = hash!("hola"); // calculado en tiempo de compilación
Cantidad de parámetros variables para *templates*:
- Esto permite implementar tuplas u otros algoritmos que inherentemente
- deben tomar parámetros variables en tiempo de compilación.
+ Esto permite implementar tuplas u otros algoritmos que inherentemente deben
+ tomar parámetros variables en tiempo de compilación.
Ejemplo::
*CTFE* (*compile-time function execution*):
si una función cumple ciertas reglas básicas (como por ejemplo no tener
- efectos colaterales) puede ser ejecutada en tiempo de compilación en vez
- de tiempo de ejecución. Esto permite hacer algunos cálculos que no
- cambian de ejecución en ejecución al momento de compilar, mejorando la
- performance o permitiendo formas avanzadas de metaprogramación. Esta
- característica se vuelve particularmente útil al combinarse con *string
- mixins*.
+ efectos colaterales) puede ser ejecutada en tiempo de compilación en vez de
+ tiempo de ejecución. Esto permite hacer algunos cálculos que no cambian de
+ ejecución en ejecución al momento de compilar, mejorando el rendimiento
+ o permitiendo formas avanzadas de meta-programación. Esta característica se
+ vuelve particularmente útil al combinarse con *string mixins*.
Ejemplo::
la palabra *mixin* tiene significados distintos en varios lenguajes de
programación. En D_ *mixin* significa tomar una secuencia arbitraria de
declaraciones e insertarla en el contexto (*scope*) actual. Esto puede
- realizarse a nivel global, en clases, estructuras o funciones. Esto
- sirve como un mecanismo para evitar duplicación de código que puede ser
+ realizarse a nivel global, en clases, estructuras o funciones. Esto sirve
+ como un mecanismo para evitar duplicación de código que puede ser
introducida por la falta de herencia múltiple.
Ejemplo::
*String mixin* se refiere a la capacidad de *incrustar* un *string* que
contenga un fragmento de código en un programa como si este fragmento
- hubiera sido escrito en el código fuente directamente por el
- programador. Esto permite hacer manipulaciones arbitrariamente
- complejas en combinación con funciones ejecutadas en tiempo de
- compilación.
+ hubiera sido escrito en el código fuente directamente por el programador.
+ Esto permite hacer manipulaciones arbitrariamente complejas en combinación
+ con funciones ejecutadas en tiempo de compilación.
Ejemplo::
Más información en http://www.digitalmars.com/d/1.0/mixin.html
Expresiones ``is``:
- las *expresiones ``is``* permiten la compilación condicional basada en
- las características de un tipo. Esto se realiza en favor a una técnica
- utilizada en C++ de realizar *pattern matching* sobre los parámetros de
- las plantillas.
+ las *expresiones ``is``* permiten la compilación condicional basada en las
+ características de un tipo. Esto se realiza en favor a una técnica
+ utilizada en C++ de realizar *pattern matching* sobre los parámetros de las
+ plantillas.
Ejemplo::
return T.init;
}
- Esto provee además una forma simple de reflexión en tiempo de
- compilación.
+ Esto provee además una forma simple de reflexión en tiempo de compilación.
Más información en
http://www.digitalmars.com/d/1.0/expression.html#IsExpression
Programación de bajo nivel (*system programming*)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-Por programación de bajo nivel nos referimos a la capacidad de un lenguaje
-de manipular el hardware directamente, o al menos la memoria. C es
-probablemente el lenguaje de bajo nivel más popular, seguido por C++.
+Por programación de bajo nivel nos referimos a la capacidad de un lenguaje de
+manipular el hardware directamente, o al menos la memoria. C es probablemente
+el lenguaje de bajo nivel más popular, seguido por C++.
D_ presenta muchas características de bajo nivel:
Compila a código de máquina nativo:
- no es interpretado ni necesita una máquina virtual como otros lenguajes
- de más alto nivel como Java_, `C#`_, Python_, etc.
+ no es interpretado ni necesita una máquina virtual como otros lenguajes de
+ más alto nivel como Java_, `C#`_, Python_, etc.
Provee acceso a *assembly*:
por lo tanto, acceso directo al *hardware* y la posibilidad de utilizar
cualquier característica de éste que no esté disponible en el lenguaje.
- Una ventaja sobre C y C++ es que el lenguaje *assembly* utilizado dentro
- de D_ está especificado, por lo que se puede mantener la portabilidad
- entre compiladores incluso cuando se utiliza *assembly* (mientras que no
- se cambie de arquitectura, por supuesto).
+ Una ventaja sobre C y C++ es que el lenguaje *assembly* utilizado dentro de
+ D_ está especificado, por lo que se puede mantener la portabilidad entre
+ compiladores incluso cuando se utiliza *assembly* (mientras que no se
+ cambie de arquitectura, por supuesto).
``goto``:
al igual que C y C++, D_ provee la flexibilidad del uso de ``goto``.
printf("3 + 5 == %d\n", 3 + 5); // llama al printf de C
Manejo de memoria explícito:
- permite alocar estructuras en el *stack* o en el *heap*, haciendo uso de
+ permite asignar estructuras en el *stack* o en el *heap*, haciendo uso de
los servicios del sistema operativo o la biblioteca estándar de C.
Objetos y arreglos *livianos*:
por objetos *livianos* se entiende no-polimórficos. Es decir, un
- agrupamiento de variables análogo al ``struct`` de C, sin tabla virtual
- ni otro tipo de *overhead*. Los arreglos *livianos* son arreglos
- estáticos como en C, cuyo tamaño es fijo, también sin ningún tipo de
- *overhead* como C. Además puede alocarse un arreglo dinámicamente usando
- ``malloc()`` y utilizar el operador ``[]`` para accederlo.
+ agrupamiento de variables análogo al ``struct`` de C, sin tabla virtual ni
+ otro tipo de *overhead*. Los arreglos *livianos* son arreglos estáticos
+ como en C, cuyo tamaño es fijo, también sin ningún tipo de *overhead* como
+ C. Además puede asignarse un arreglo dinámicamente usando ``malloc()``
+ y utilizar el operador ``[]`` para accederlo.
- Esto también permite interoperar con C, ya que pueden definirse
- ``structs`` y arreglos que pueden ser intercambiados con dicho lenguaje
- sin problemas.
+ Esto también permite interoperar con C, ya que pueden definirse ``structs``
+ y arreglos que pueden ser intercambiados con dicho lenguaje sin problemas.
Ejemplo::
Rendimiento:
la :ref:`d_generic` permite realizar muchas optimizaciones ya que se
resuelve en tiempo de compilación y por lo tanto aumentando la
- *performance* en la ejecución.
+ rendimiento en la ejecución.
Número de punto flotante de 80 bits:
El tipo ``real`` de D_ tiene precisión de 80 bits si la plataforma lo
Programación de alto nivel
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-Programa de alto nivel se refiere a construcciones más avanzadas que un
-loop. Expresiones semánticamente más ricas que permiten mayor expresividad
-al programador o le permiten focalizarse de mejora manera en los algoritmos
-independizándose del *hardware* o de como funciona una computadora. Es
-exactamente el opuesto a :ref:`d_low_level`.
+Programación de alto nivel se refiere a construcciones más avanzadas que una
+sentencia para iterar; expresiones con una semántica más ricas que permiten
+mayor expresividad al programador o le permiten focalizarse de mejora manera
+en los algoritmos independizándose del *hardware* o de como funciona una
+computadora. Es exactamente el opuesto a :ref:`d_low_level`.
-En general estas características tiene como efecto secundario una mejora de
-la productividad de los programadores. D_ adopta herramientas de muchos
-lenguajes de alto nivel, como Java_ y Python_, por ejemplo:
+En general estas características tiene como efecto secundario una mejora de la
+productividad de los programadores. D_ adopta herramientas de muchos lenguajes
+de alto nivel, como Java_ y Python_, por ejemplo:
Manejo automático de memoria:
al igual que C/C++ y prácticamente cualquier lenguaje imperativo maneja
automáticamente el *stack*, pero a diferencia de la mayoría de los
- lenguajes de bajo nivel, D_ permite manejar el *heap* de manera
- automática también a través de un *recolección de basura*.
+ lenguajes de bajo nivel, D_ permite manejar el *heap* de manera automática
+ también a través de un *recolección de basura*.
Sistema de paquetes y módulos (similar a Java_ o Python_):
un módulo es una unidad que agrupa clases, funciones y cualquier otra
construcción de lenguaje. Un paquete es una agrupación de módulos. D_
asocia un módulo a un archivo fuente (y un archivo objeto cuando éste es
- compilado) y un paquete a un directorio. A diferencia de C/C++ no
- necesita de un preprocesador para incluir declaraciones de otros
- *módulos* (en C/C++ no existe el concepto de módulo, solo de unidades de
- compilación).
+ compilado) y un paquete a un directorio. A diferencia de C/C++ no necesita
+ de un preprocesador para incluir declaraciones de otros *módulos* (en C/C++
+ no existe el concepto de módulo, solo de unidades de compilación).
Ejemplo:
f(); // ejecuta b.f()
Funciones y delegados:
- las funciones pueden ser sobrecargadas (funciones con el mismo nombre
- pero distinta cantidad o tipo de parámetros), pueden especificarse
- argumentos de entrada, salida o entrada/salida, argumentos por omisión
- o argumentos evaluados de forma perezosa (*lazy*). Además pueden tener
- una cantidad de argumentos variables pero manteniendo información de
- tipos (más seguro que C/C++).
+ las funciones pueden ser sobrecargadas (funciones con el mismo nombre pero
+ distinta cantidad o tipo de parámetros), pueden especificarse argumentos de
+ entrada, salida o entrada/salida, argumentos por omisión o argumentos
+ evaluados de forma perezosa (*lazy*). Además pueden tener una cantidad de
+ argumentos variables pero manteniendo información de tipos (más seguro que
+ C/C++).
Los *delegados* son punteros a función con un contexto asociado. Este
contexto puede ser un objeto (en cuyo caso la función es un método) o un
*stack frame* (en cuyo caso la función es una función anidada).
Además de esto los delegados son ciudadanos de primera clase
- [#1stclasscity]_, disponiendo de forma literal (delegado anónimo), lo
- que permite construcciones de alto nivel muy conveniente. Los argumentos
- evaluados de forma perezosa no son más que un delegado que se ejecuta
- solo cuando es necesario.
+ [#1stclasscity]_, disponiendo de forma literal (delegado anónimo), lo que
+ permite construcciones de alto nivel muy conveniente. Los argumentos
+ evaluados de forma perezosa no son más que un delegado que se ejecuta solo
+ cuando es necesario.
.. [#1stclasscity] Por ciudadano de primera clase se entiende que se trata
de un tipo soportado por completo por el lenguaje, disponiendo de
Arreglos *dinámicos* y arreglos asociativos:
los arreglos *dinámicos* son arreglos de longitud variable manejados
automáticamente por el lenguaje (análogos al ``std::vector`` de C++).
- Soportan concatenación (a través del operador ``~``), rebanado
- o *slicing* (a través del operador ``[x..y]``) y chequeo de límites
- (*bound checking*).
+ Soportan concatenación (a través del operador ``~``), rebanado o *slicing*
+ (a través del operador ``[x..y]``) y chequeo de límites (*bound checking*).
- Los arreglos asociativos (también conocidos como *hashes*
- o diccionarios) también son provistos por el lenguaje.
+ Los arreglos asociativos (también conocidos como *hashes* o diccionarios)
+ también son provistos por el lenguaje.
Ambos son ciudadanos de primera clase, disponiendo de forma literal.
*Strings*:
al igual que los delegados y arreglos dinámicos y asociativos, los
- *strings* son ciudadanos de primera clase, teniendo forma literal
- y siendo codificados en UTF-8/16/32. Son un caso particular de arreglo
- dinámico y es posible utilizarlos en sentencias ``switch``/``case``.
+ *strings* son ciudadanos de primera clase, teniendo forma literal y siendo
+ codificados en UTF-8/16/32. Son un caso particular de arreglo dinámico y es
+ posible utilizarlos en sentencias ``switch``/``case``.
Ejemplo::
``typedef`` y ``alias``:
el primero define un nuevo tipo basado en otro. A diferencia de C/C++ el
- tipo original no puede ser implícitamente convertido al tipo nuevo
- (excepto valores literales), pero la conversión es válida en el otro
- sentido (similar a los ``enum`` en C++). Por el contrario, ``alias`` es
- análogo al ``typedef`` de C/C++ y simplemente es una forma de referirse
- al mismo tipo con un nombre distinto.
+ tipo original no puede ser implícitamente convertido al tipo nuevo (excepto
+ valores literales), pero la conversión es válida en el otro sentido
+ (similar a los ``enum`` en C++). Por el contrario, ``alias`` es análogo al
+ ``typedef`` de C/C++ y simplemente es una forma de referirse al mismo tipo
+ con un nombre distinto.
Ejemplo::
Documentación embebida:
D_ provee un sistema de documentación embebida, análogo a lo que provee
- Java_ o Python_ en menor medida. Hay comentarios especiales del código
- que pueden ser utilizados para documentarlo de forma tal que luego el
+ Java_ o Python_ en menor medida. Hay comentarios especiales del código que
+ pueden ser utilizados para documentarlo de forma tal que luego el
compilador pueda extraer esa información para generar un documento.
Más información en http://www.digitalmars.com/d/1.0/ddoc.html
Objetos *pesados*:
objetos polimórficos como los de cualquier lenguaje con orientación real
- a objetos. Estos objetos poseen una tabla virtual para *dispatch*
- dinámico, todos los métodos son virtuales a menos que se indique lo
- contrario y tienen semántica de referencia [#drefsem]_. Estos objetos
- tienen un *overhead* comparados a los objetos *livianos* pero aseguran
- una semántica segura para trabajar con orientación a objetos, evitando
- problemas con los que se enfrenta C++ (como *slicing* [#dslicing]_)
- debido a que permite semántica por valor [#dvalsem]_.
+ a objetos. Estos objetos poseen una tabla virtual para despacho dinámico,
+ todos los métodos son virtuales a menos que se indique lo contrario
+ y tienen semántica de referencia [#drefsem]_. Estos objetos tienen un
+ *overhead* comparados a los objetos *livianos* pero aseguran una semántica
+ segura para trabajar con orientación a objetos, evitando problemas con los
+ que se enfrenta C++ (como *slicing* [#dslicing]_) debido a que permite
+ semántica por valor [#dvalsem]_.
.. [#drefsem] Semántica de referencia significa que el tipo es tratado como
si fuera un puntero. Nunca se hacen copias del objeto, siempre se pasa
por referencia.
-
.. [#dslicing] Este problema se da en C++ cuando se pasa una clase derivada
a una función que acepta una clase base por valor como parámetro. Al
realizarse una copia de la clase con el constructor de copia de la clase
base, se pierden (o *rebanan*) los atributos de la clase derivada, y la
información de tipos en tiempo de ejecución (*RTTI*).
-
.. [#dvalsem] Semántica de valor significa que el tipo es tratado como si
fuera un valor concreto. En general se pasa por valor y se hacen copias
a menos que se utilice explícitamente un puntero.
Interfaces:
D_ no soporta herencia múltiple pero sí interfaces. Una interfaz es
- básicamente una tabla virtual, una definición de métodos virtuales que
- debe proveer una clase. Las interfaces no proveen una implementación de
- dichos métodos, ni pueden tener atributos. Esto simplifica mucho el
- lenguaje y no se pierde flexibilidad porque puede conseguirse el mismo
- efecto de tener herencia múltiple a través de interfaces y *mixins* para
- proveer una implementación o atributos en común a varias clases que
- implementan la misma interfaz.
+ básicamente una tabla virtual, una definición de métodos virtuales que debe
+ proveer una clase. Las interfaces no proveen una implementación de dichos
+ métodos, ni pueden tener atributos. Esto simplifica mucho el lenguaje y no
+ se pierde flexibilidad porque puede conseguirse el mismo efecto de tener
+ herencia múltiple a través de interfaces y *mixins* para proveer una
+ implementación o atributos en común a varias clases que implementan la
+ misma interfaz.
Sobrecarga de operadores:
la sobrecarga de operadores permite que un objeto tenga una sintaxis
}
}
- Esto tiene un pequeño *overhead* ya que la clase ``Anidada`` debe
- guardar un puntero a la clase ``Exterior``. Si no se necesita este
- comportamiento es posible evitar este *overhead* utilizando ``static``,
- en cuyo caso solo puede acceder a atributos estáticos de la clase
- ``Exterior``.
+ Esto tiene un pequeño *overhead* ya que la clase ``Anidada`` debe guardar
+ un puntero a la clase ``Exterior``. Si no se necesita este comportamiento
+ es posible evitar este *overhead* utilizando ``static``, en cuyo caso solo
+ puede acceder a atributos estáticos de la clase ``Exterior``.
Ejemplo::
``alignof``
alineación de una estructura o tipo.
- Estos son solo los *properties* predefinidos para todos los tipos, pero
- hay una cantidad considerable de *properties* extra para cada tipo.
+ Estos son solo los *properties* predefinidos para todos los tipos, pero hay
+ una cantidad considerable de *properties* extra para cada tipo.
Más información sobre *properties* de clases en
http://www.digitalmars.com/d/1.0/property.html#classproperties y sobre
+.. _d_dbc:
+
Programación confiable
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-Programación confiable se refiere a las capacidades o facilidades que
-provee el lenguaje para evitar fallas de manera temprano (o la capacidad de
-evitar que ciertas fallas puedan existir directamente). D_ presta
-particular atención a esto y provee las siguientes herramientas:
+Programación confiable se refiere a las capacidades o facilidades que provee
+el lenguaje para evitar fallas de manera temprano (o la capacidad de evitar
+que ciertas fallas puedan existir directamente). D_ presta particular atención
+a esto y provee las siguientes herramientas:
Excepciones:
- D_ soporta excepciones de manera similar a Java_: provee ``try``,
- ``catch`` y ``finally``. Esto permite que los errores difícilmente pasen
+ D_ soporta excepciones de manera similar a Java_: provee ``try``, ``catch``
+ y ``finally``. Esto permite que los errores difícilmente pasen
silenciosamente sin ser detectados.
``assert``:
- es una condición que debe cumplirse siempre en un programa, como un
- chequeo de integridad. Esto es muy utilizado en C/C++, donde
- ``assert()`` es una *macro* que solo se compila cuando la *macro*
- ``NDEBUG`` no está definida. Esto permite eliminar los chequeos de
- integridad del programa, que pueden ser costosos, para versiones que se
- suponen estables.
+ es una condición que debe cumplirse siempre en un programa, como un chequeo
+ de integridad. Esto es muy utilizado en C/C++, donde ``assert()`` es una
+ *macro* que solo se compila cuando la *macro* ``NDEBUG`` no está definida.
+ Esto permite eliminar los chequeos de integridad del programa, que pueden
+ ser costosos, para versiones que se suponen estables.
D_ lleva este concepto más allá y hace al ``assert`` parte del lenguaje.
- Si una verificación no se cumple, lanza una excepción. El ``assert`` no
- es compilado cuando se utiliza una opción del compilador.
+ Si una verificación no se cumple, lanza una excepción. El ``assert`` no es
+ compilado cuando se utiliza una opción del compilador.
Ejemplo::
assert (f.ok());
Diseño por contrato:
- el diseño por contrato es un concepto introducido por el lenguaje
- Eiffel_ a mediados/finales de los '80. Se trata de incorporar en el
- lenguaje las herramientas para poder aplicar verificaciones formales
- a las interfaces de los programas.
+ el diseño por contrato es un concepto introducido por el lenguaje Eiffel_
+ a mediados/finales de los '80. Se trata de incorporar en el lenguaje las
+ herramientas para poder aplicar verificaciones formales a las interfaces de
+ los programas.
D_ implementa las siguientes formas de diseño por contrato (todas se
- ejecutan siempre y cuando no se compile en modo *release*, de manera de
- no sacrificar *performance* cuando es necesario):
+ ejecutan siempre y cuando no se compile en modo *release*, de manera de no
+ sacrificar rendimiento cuando es necesario):
Pre y post condiciones:
Ejemplo::
}
Invariantes de representación:
- La invariante de representación es un método de una clase
- o estructura que es verificada cuando se completa su construcción,
- antes de la destrucción, antes y después de ejecutar cualquier
- función miembro pública y cuando se lo requiere de forma explícita
- utilizando ``assert``.
+ La invariante de representación es un método de una clase o estructura
+ que es verificada cuando se completa su construcción, antes de la
+ destrucción, antes y después de ejecutar cualquier función miembro
+ pública y cuando se lo requiere de forma explícita utilizando
+ ``assert``.
Ejemplo::
a diferencia de C++, D_ garantiza el orden de inicialización de los
módulos. Si bien en C++ no hay módulos si no unidades de compilación, es
posible que se ejecute código antes del ``main()`` en C++, si hay, por
- ejemplo, instancias globales con un constructor definido. C++ no
- garantiza un orden de inicialización, lo que trae muchos problemas. En
- D_ se define el orden de inicialización y es el mismo orden en que el
- usuario importa los módulos.
+ ejemplo, instancias globales con un constructor definido. C++ no garantiza
+ un orden de inicialización, lo que trae muchos problemas. En D_ se define
+ el orden de inicialización y es el mismo orden en que el usuario importa
+ los módulos.
Inicialización garantizada:
todas las variables son inicializadas por el lenguaje (a menos que el
usuario pida explícitamente que no lo sean). Siempre que sea posible se
- elijen valores de inicialización que permitan saber al programador que
- la variable no fue inicializada explícitamente, de manera de poder
- detectar errores de manera temprana.
+ elijen valores de inicialización que permitan saber al programador que la
+ variable no fue inicializada explícitamente, de manera de poder detectar
+ errores de manera temprana.
Ejemplo::
- double d; // inicializado a NaN
- int x; // inicializado a 0
- Fecha f; // inicializado a null
- byte[5] a; // inicializados todos los valores a 0
+ double d; // inicializado a NaN
+ int x; // inicializado a 0
+ Fecha f; // inicializado a null
+ byte[5] a; // inicializados todos los valores a 0
long l = void; // NO inicializado (explícitamente)
*RAII* (*Resource Adquisition Is Initialization*):
- es una técnica muy utilizada en C++ que consiste en reservar recursos
- por medio de la construcción de un objeto y liberarlos cuando se libera
- éste. Al llamarse al destructor de manera automática cuando se sale del
- *scope*, se asegura que el recurso será liberado también.
+ es una técnica muy utilizada en C++ que consiste en reservar recursos por
+ medio de la construcción de un objeto y liberarlos cuando se libera éste.
+ Al llamarse al destructor de manera automática cuando se sale del *scope*,
+ se asegura que el recurso será liberado también.
Esta técnica es la base para desarrollar código seguro en cuanto
a excepciones (*exception-safe*) [SUTT99]_.
- En D_ no es tan común utilizar *RAII* dada la existencia del recolector
- de basura (en la mayoría de los casos el recurso a administrar es
+ En D_ no es tan común utilizar *RAII* dada la existencia del recolector de
+ basura (en la mayoría de los casos el recurso a administrar es
sencillamente memoria). Sin embargo en los casos en donde es necesario,
puede utilizarse *RAII* mediante la utilización de la palabra reservada
``scope``, que limita la vida de un objeto un bloque de código.
} // en este punto se llama al destructor de archivo
Guardias de bloque (*scope guards*):
- además de poder limitar la vida de una instancia a un *scope*, es
- posible especificar un bloque de código arbitrario a ejecutar al
- abandonar un *scope*, ya sea cuando se sale del *scope* normalmente
- o por una falla.
+ además de poder limitar la vida de una instancia a un *scope*, es posible
+ especificar un bloque de código arbitrario a ejecutar al abandonar un
+ *scope*, ya sea cuando se sale del *scope* normalmente o por una falla.
Ejemplo::
int f(Lock lock) {
lock.lock();
scope (exit)
- lock.unlock(); // ejecutado siempre que salga de f()
+ lock.unlock(); // ejecutado siempre que salga de f()
auto trans = new Transaccion;
scope (success)
- trans.commit(); // ejecutado si sale con "return"
+ trans.commit(); // ejecutado si sale con "return"
scope (failure)
- trans.rollback(); // ejecutado si sale por una excepción
+ trans.rollback(); // ejecutado si sale por una excepción
if (condicion)
- throw Exception("error"); // ejecuta lock.unlock() y trans.rollback()
+ throw Exception("error"); // lock.unlock() y trans.rollback()
else if (otra_condicion)
- return 5; // ejecuta lock.unlock() y trans.commit()
- return 0; // ejecuta lock.unlock() y trans.commit()
+ return 5; // lock.unlock() y trans.commit()
+ return 0; // lock.unlock() y trans.commit()
}
- Esta es una nueva forma de poder escribir código *exception-safe*,
- aunque el programador debe tener un poco más de cuidado de especificar
- las acciones a ejecutar al finalizar el *scope*.
+ Esta es una nueva forma de poder escribir código *exception-safe*, aunque
+ el programador debe tener un poco más de cuidado de especificar las
+ acciones a ejecutar al finalizar el *scope*.
Primitivas de sincronización de hilos:
la programación multi-hilo está directamente soportada por el lenguaje,
- y se provee una primitiva de sincronización al igual que Java_. La
- palabra reservada ``synchronized`` puede aparecer como modificador de
- métodos (en cuyo caso se utiliza un *lock* por clase para sincronizar)
- o como una sentencia, en cuyo caso se crea un *lock* global por cada
- bloque ``synchronized`` a menos que se especifique sobre qué objeto
- realizar la sincronización. Por ejemplo::
+ y se provee una primitiva de sincronización al igual que Java_. La palabra
+ reservada ``synchronized`` puede aparecer como modificador de métodos (en
+ cuyo caso se utiliza un *lock* por clase para sincronizar) o como una
+ sentencia, en cuyo caso se crea un *lock* global por cada bloque
+ ``synchronized`` a menos que se especifique sobre qué objeto realizar la
+ sincronización. Por ejemplo::
class Foo {
synchronized void bar() { /* cuerpo */ }
DMD_ es el compilador de referencia, escrito por `Walter Bright`_. El
*front-end* [#frontend]_ de este compilador ha sido liberado bajo licencia
-Artistic_/GPL_ y es utilizado por los otros dos compiladores, por lo
-tanto en realidad hay solo un compilador disponible con 3 *back-ends*
-[#backend]_ diferentes.
+Artistic_/GPL_ y es utilizado por los otros dos compiladores, por lo tanto en
+realidad hay solo un compilador disponible con 3 *back-ends* [#backend]_
+diferentes.
.. [#frontend] *Front-end* es la parte del compilador encargada de hacer el
análisis léxico, sintáctico y semántico del código fuente, generando una
la representación intermedia generada por el *front-end* a código de
máquina.
-Con `DMD 1.041`__ se publicó el código fuente completo del compilador,
-pero con una licencia muy restrictiva para uso personal, por lo que el
-único efecto logrado por esto es que la gente pueda mandar parches
-o correcciones del compilador pero no lo convierte en `Software Libre`_,
-siendo el único de los 3 compiladores que no tiene esta característica.
+Con `DMD 1.041`__ se publicó el código fuente completo del compilador, pero
+con una licencia muy restrictiva para uso personal, por lo que el único efecto
+logrado por esto es que la gente pueda mandar parches o correcciones del
+compilador pero no lo convierte en `Software Libre`_, siendo el único de los
+3 compiladores que no tiene esta característica.
__ http://www.digitalmars.com/d/1.0/changelog.html#new1_041
El compilador GDC_ es el *front-end* de DMD_ utilizando al compilador GCC_
como *back-end*. Fue un muy buen compilador pero en la actualidad está
-abandonado. No hay un *release* desde agosto de 2007 y no hay
-actualizaciones serias del código desde mediados de 2008, por lo que no
-parece haber muchas probabilidades de que se siga manteniendo.
-
-LDC_ es lo opuesto; un compilador joven, nacido a mediados de 2007 (aunque
-vio la luz un año después aproximadamente), su primer *release* fue
-a principios de 2009 y tuvo un crecimiento excepcional. En la actualidad
-inclusive pasa más pruebas de estrés que el compilador de referencia DMD_.
-Como *back-end* utiliza LLVM_, otro proyecto joven y con una tasa de
-crecimiento muy alta.
-
-Además de estos compiladores hay varios otros experimentales, pero ninguno
-de ellos de calidad suficiente todavía. Por ejemplo hay un compilador
-experimental que emite *CIL* (*Common Intermediate Language*), el
-*bytecode* de `.NET`_, llamado DNet_. También hay un *fron-end* escrito en
-D_, llamado Dil_
+abandonado. No hay un *release* desde agosto de 2007 y no hay actualizaciones
+serias del código desde mediados de 2008, por lo que no parece haber muchas
+probabilidades de que se siga manteniendo.
+
+LDC_ es lo opuesto; un compilador joven, nacido a mediados de 2007 (aunque vio
+la luz un año después aproximadamente), su primer *release* fue a principios
+de 2009 y tuvo un crecimiento excepcional. En la actualidad inclusive pasa más
+pruebas de estrés que el compilador de referencia DMD_. Como *back-end*
+utiliza LLVM_, otro proyecto joven y con una tasa de crecimiento muy alta.
+
+Además de estos compiladores hay varios otros experimentales, pero ninguno de
+ellos de calidad suficiente todavía. Por ejemplo hay un compilador
+experimental que emite *CIL* (*Common Intermediate Language*), el *bytecode*
+de `.NET`_, llamado DNet_. También hay un *fron-end* escrito en D_, llamado
+Dil_
Originalmente, dado que GDC_ estaba siendo mantenido y que LDC_ no existía,
-este trabajo iba a ser realizado utilizando GDC_ como compilador, dado que
-al ser `Software Libre`_ podía ser modificado de ser necesario. Finalmente,
-gracias a la excepcional tasa de crecimiento de LDC_ y al abandono de GDC_
-se terminó desarrollando el trabajo utilizando LDC_.
+este trabajo iba a ser realizado utilizando GDC_ como compilador, dado que al
+ser `Software Libre`_ podía ser modificado de ser necesario. Finalmente,
+gracias a la excepcional tasa de crecimiento de LDC_ y al abandono de GDC_ se
+terminó desarrollando el trabajo utilizando LDC_.