X-Git-Url: https://git.llucax.com/z.facultad/75.00/informe.git/blobdiff_plain/b0956c037ae52da777b06705157486067755ec2c..3574dc3e457331aed8212c161d539ad5f69665d5:/source/d.rst?ds=sidebyside diff --git a/source/d.rst b/source/d.rst index f916af0..f3f90db 100644 --- a/source/d.rst +++ b/source/d.rst @@ -5,7 +5,7 @@ ESTADO: TERMINADO -.. _ref_d: +.. _d_lang: El lenguaje de programación D ============================================================================ @@ -15,109 +15,103 @@ Historia ---------------------------------------------------------------------------- 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: - Parece que la mayoría de los lenguajes de programación "nuevos" caen - en 2 categorías: aquellos académicos con nuevos paradigmas radicales y - aquellos de grandes corporaciones con el foco en el desarrollo rápido - y web. Tal vez es hora de que nazca un nuevo lenguaje de la experiencia - práctica implementando compiladores. + Parece que la mayoría de los lenguajes de programación "nuevos" caen en + 2 categorías: aquellos académicos con nuevos paradigmas radicales + y aquellos de grandes corporaciones con el foco en el desarrollo rápido + 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 +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 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 @@ -125,29 +119,29 @@ 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. +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. 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: +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: 1. Análisis léxico. 2. Análisis sintáctico. @@ -155,25 +149,25 @@ en pequeños pasos bien separados: 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: + -.. _ref_d_generic: +.. _d_generic: Programación genérica y meta-programación ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -181,519 +175,513 @@ Programación genérica y meta-programación 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:: + Ejemplo:: - static if ((void*).sizeof == 4) - pragma(msg, "32 bits"); + static if ((void*).sizeof == 4) + pragma(msg, "32 bits"); - Más información en http://www.digitalmars.com/d/1.0/version.html#staticif + 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 inicializador. - Ejemplo:: + Ejemplo:: - static i = 5; // i es int - const d = 6.0; // d es double - auto s = "hola"; // s es string (que es un alias de char[]) + static i = 5; // i es int + const d = 6.0; // d es double + auto s = "hola"; // s es string (que es un alias de char[]) - Más información en - http://www.digitalmars.com/d/1.0/declaration.html#AutoDeclaration + 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:: + Ejemplo:: - typeof(5 + 6.0) d; // d es double + typeof(5 + 6.0) d; // d es double - Más información en http://www.digitalmars.com/d/1.0/declaration.html#typeof + Más información en http://www.digitalmars.com/d/1.0/declaration.html#typeof 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``. + cualquier tipo de colección (arreglos estáticos y dinámicos, arreglos + asociativos, clases, estructuras o delegados) puede ser iterada mediante la + sentencia ``foreach``. - Ejemplo:: + Ejemplo:: - int[] a = [ 1, 2, 3 ]; - int total = 0; - foreach (i; a) - total += i; + int[] a = [ 1, 2, 3 ]; + int total = 0; + foreach (i; a) + 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 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. - Ejemplo:: + Ejemplo:: - T sumar(T)(T x, T y) { return x + y; } - auto i = sumar!(int)(5, 6); // i == 11 - auto f = sumar!(float)(5, 6); // j == 11.0f + T sumar(T)(T x, T y) { return x + y; } + 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 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. - Ejemplo:: + Ejemplo:: - template bloque(T, U) { - T x; - U foo(T y); - } + template bloque(T, U) { + T x; + U foo(T y); + } - bloque!(int, float).x = 5; - float f = bloque!(int, float).foo(7); + bloque!(int, float).x = 5; + float f = bloque!(int, float).foo(7); - La utilidad más prominente de los bloques parametrizados se da al - acompañarse de *mixins*. + La utilidad más prominente de los bloques parametrizados se da al + acompañarse de *mixins*. Instanciación implícita de funciones parametrizadas: - el lenguaje es capaz de deducir los parámetros siempre que no hayan - ambigüedades + el lenguaje es capaz de deducir los parámetros siempre que no hayan + ambigüedades - Ejemplo:: + Ejemplo:: - auto i = sumar(5, 6); // i == 11 - auto f = sumar(5.0f, 6.0f); // f == 11.0f + auto i = sumar(5, 6); // i == 11 + 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:: + Ejemplo de especialización:: - T sumar(T: int)(T x, T y) { return x + y + 1; } - auto i = sumar(5, 6); // i == 12 - auto f = sumar(5.0f, 6.0f) // f == 11.0f + T sumar(T: int)(T x, T y) { return x + y + 1; } + auto i = sumar(5, 6); // i == 12 + auto f = sumar(5.0f, 6.0f) // f == 11.0f - Ejemplo de especialización parcial:: + Ejemplo de especialización parcial:: - T sumar(T: T*)(T x, T y) { return *x + *y; } - int x = 5, y = 6; - auto i = sumar(&x, &y); // i == 11 - float v = 5.0f, w = 6.0f; - auto f = sumar(&v, &w); // f == 11.0f + T sumar(T: T*)(T x, T y) { return *x + *y; } + int x = 5, y = 6; + auto i = sumar(&x, &y); // i == 11 + float v = 5.0f, w = 6.0f; + auto f = sumar(&v, &w); // f == 11.0f 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. - - Ejemplo:: - - template hash(string s, uint so_far=0) { - static if (s.length == 0) - const hash = sofar; - else - const hash = hash!(s[1 .. length], sofar * 11 + s[0]); - } - string s = hash!("hola"); // calculado en tiempo de compilación + 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. + + Ejemplo:: + + template hash(string s, uint so_far=0) { + static if (s.length == 0) + const hash = sofar; + else + const hash = hash!(s[1 .. length], sofar * 11 + s[0]); + } + 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:: + Ejemplo:: - double sumar(T...)(T t) { - double res = 0.0; - foreach (x; t) - res += x; - return res; - } - double d = sumar(1, 2.0, 3.0f, 4l); // d == 10.0 + double sumar(T...)(T t) { + double res = 0.0; + foreach (x; t) + res += x; + return res; + } + double d = sumar(1, 2.0, 3.0f, 4l); // d == 10.0 *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*. - - Ejemplo:: - - int factorial(int n) { - if (n == 1) - return 1; - else - return n * factorial(n - 1); - } - static int x = factorial(5); // calculado en tiempo de compilación - int x = factorial(5); // calculado en tiempo de ejecución - - Esta característica es vital para evitar la duplicación de código. + 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*. + + Ejemplo:: + + int factorial(int n) { + if (n == 1) + return 1; + else + return n * factorial(n - 1); + } + static int x = factorial(5); // calculado en tiempo de compilación + int x = factorial(5); // calculado en tiempo de ejecución + + Esta característica es vital para evitar la duplicación de código. *Mixins*, incluyendo *string mixins*: - 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 - introducida por la falta de herencia múltiple. - - Ejemplo:: - - class A { - mixin bloque!(int, float); - } - A a = new A; - a.x = 5; - float f = a.foo(a.x); - - class B { - mixin bloque!(long, double); - } - B b = new B; - b.x = 5l; - double d = a.foo(a.x); - - *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. - - Ejemplo:: - - string generar_sumar(string var_x, string var_y) { - return "return " ~ var_x ~ " + " ~ var_y ~ ";"; - } - - int sumar(int a, int b) { - mixin(generar_sumar!("a", b")); - } - - Más información en http://www.digitalmars.com/d/1.0/mixin.html + 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 + introducida por la falta de herencia múltiple. -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. + Ejemplo:: + + class A { + mixin bloque!(int, float); + } + A a = new A; + a.x = 5; + float f = a.foo(a.x); + + class B { + mixin bloque!(long, double); + } + B b = new B; + b.x = 5l; + double d = a.foo(a.x); - 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. + + Ejemplo:: + + string generar_sumar(string var_x, string var_y) { + return "return " ~ var_x ~ " + " ~ var_y ~ ";"; + } - T foo(T)(T x) { - static if (is(T == class)) - return new T; - else - return T.init; - } + int sumar(int a, int b) { + mixin(generar_sumar!("a", b")); + } + + 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. + + Ejemplo:: + + T foo(T)(T x) { + static if (is(T == class)) + return new T; + else + 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 + Más información en + http://www.digitalmars.com/d/1.0/expression.html#IsExpression -.. _ref_d_low_level: +.. _d_low_level: 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. + 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``. + al igual que C y C++, D_ provee la flexibilidad del uso de ``goto``. -Compatibilidad con C - soporta todos los tipos de C y es ABI [#abi]_ compatible con éste. Esto - permite enlazar archivos objeto estándar de C y D_ en un mismo programa. - Además permite interoperar con C a través de ``extern (C)``. +Compatibilidad con C: + soporta todos los tipos de C y es ABI [#abi]_ compatible con éste. Esto + permite enlazar archivos objeto estándar de C y D_ en un mismo programa. + Además permite interoperar con C a través de ``extern (C)``. - Ejemplo:: + .. [#abi] Interfaz de Aplicación Binaria (del inglés *Application Binary + Interface*). - extern (C) printf(const char* format, ...); - printf("3 + 5 == %d\n", 3 + 5); // llama al printf de C + Ejemplo:: + + extern (C) printf(const char* format, ...); + 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 - los servicios del sistema operativo o la biblioteca estándar de C. + 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. - - Esto también permite interoperar con C, ya que pueden definirse - ``structs`` y arreglos que pueden ser intercambiados con dicho lenguaje - sin problemas. - - Ejemplo:: - - struct timeval { - time_t tv_sec; - suseconds_t tv_usec; - } - extern (C) { - void* malloc(size_t); - size_t strlen(const char *); - int gettimeofday(timeval *, void *); - } - char* s = cast(char*) malloc(2); - s[0] = 'C'; - s[1] = '\0'; - size_t l = strlen(s); // l == 1 - timeval tv; - gettimeofday(&tv, null); + 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 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. + + Ejemplo:: + + struct timeval { + time_t tv_sec; + suseconds_t tv_usec; + } + extern (C) { + void* malloc(size_t); + size_t strlen(const char *); + int gettimeofday(timeval *, void *); + } + char* s = cast(char*) malloc(2); + s[0] = 'C'; + s[1] = '\0'; + size_t l = strlen(s); // l == 1 + timeval tv; + gettimeofday(&tv, null); Rendimiento: - la :ref:`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. + 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. Número de punto flotante de 80 bits: - El tipo ``real`` de D_ tiene precisión de 80 bits si la plataforma lo - soporta (por ejemplo en i386). + El tipo ``real`` de D_ tiene precisión de 80 bits si la plataforma lo + soporta (por ejemplo en i386). Control de alineación de miembros de una estructura: - Mediante ``align`` se puede especificar la alineación a tener en una - estructura. + Mediante ``align`` se puede especificar la alineación a tener en una + estructura. - Ejemplo:: - - align (1) - struct paquete_de_red { - char tipo; - short valor; - } - // paquete_de_red.sizeof == 3 + Ejemplo:: + align (1) + struct paquete_de_red { + char tipo; + short valor; + } + // paquete_de_red.sizeof == 3 -.. [#abi] Interfaz de Aplicación Binaria (del inglés *Application Binary - Interface*). -.. _ref_d_high_level: +.. _d_high_level: 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 +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:`ref_d_low_level`. +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*. + 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*. 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). + 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). - Ejemplo: + Ejemplo: - ``a.d``:: + ``a.d``:: - module a; - void f() {} + module a; + void f() {} - ``b.d``:: + ``b.d``:: - module b; - void f() {} + module b; + void f() {} - ``c.d``:: + ``c.d``:: - module c; - import a; - import b: f; - a.f(); - b.f(); - f(); // ejecuta b.f() + module c; + import a; + import b: f; + a.f(); + b.f(); + 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++). - - 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. - - Ejemplo:: - - bool buscar(T[] arreglo, T item, bool delegate(T x, T y) igual) { - foreach (t, arreglo) - if (igual(t, elemento)) - return true; - return false; - } - struct Persona { - string nombre; - } - Persona[] personas; - // llenas personas - Persona p; - p.nombre = "Carlos"; - bool encontrado = buscar(personas, p, - (Persona x, Persona y) { - return x.nombre == y.nombre; - } - ); + 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] Por ciudadano de primera clase se entiende que se trata + de un tipo soportado por completo por el lenguaje, disponiendo de + expresiones literales anónimas, pudiendo ser almacenados en variables, + estructuras de datos, teniendo una identidad intrínseca, más allá de un + nombre dado, etc. En realidad los arreglos asociativos no pueden ser + expresados como literales anónimos pero sí tienen una sintaxis especial + soportada directamente por el lenguaje. + + Ejemplo:: + + bool buscar(T[] arreglo, T item, bool delegate(T x, T y) igual) { + foreach (t, arreglo) + if (igual(t, elemento)) + return true; + return false; + } + struct Persona { + string nombre; + } + Persona[] personas; + // llenas personas + Persona p; + p.nombre = "Carlos"; + bool encontrado = buscar(personas, p, + (Persona x, Persona y) { + return x.nombre == y.nombre; + } + ); 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*). + 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*). - 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. + Ambos son ciudadanos de primera clase, disponiendo de forma literal. - Ejemplo:: + Ejemplo:: - int[] primos = [ 2, 3, 5, 7, 11, 13, 17, 19 ]; - primos ~= [ 23, 29 ]; - auto menores_que_10 = primos[0..4]; // [ 2, 3, 5, 7 ] - int[string] agenda; - agenda["Pepe"] = 5555_1234; + int[] primos = [ 2, 3, 5, 7, 11, 13, 17, 19 ]; + primos ~= [ 23, 29 ]; + auto menores_que_10 = primos[0..4]; // [ 2, 3, 5, 7 ] + int[string] agenda; + agenda["Pepe"] = 5555_1234; *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``. + 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``. - Ejemplo:: + Ejemplo:: - string s = "árbol"; + string s = "árbol"; - switch (s) { - case "árbol": - s = "tree"; - default: - s = ""; - } + switch (s) { + case "árbol": + s = "tree"; + default: + s = ""; + } ``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. - - Ejemplo:: - - typedef int tipo; - int foo(tipo x) {} - tipo t = 10; - int i = 10; - foo(t); - foo(i); // error, no compila - alias tipo un_alias; - un_alias a = t; - foo(a); + 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. + + Ejemplo:: + + typedef int tipo; + int foo(tipo x) {} + tipo t = 10; + int i = 10; + foo(t); + foo(i); // error, no compila + alias tipo un_alias; + un_alias a = t; + foo(a); 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 - compilador pueda extraer esa información para generar un documento. + 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 + compilador pueda extraer esa información para generar un documento. - Más información en http://www.digitalmars.com/d/1.0/ddoc.html + Más información en http://www.digitalmars.com/d/1.0/ddoc.html Números complejos: - D_ soporta números complejos como ciudadanos de primera clase. Soporta - forma literal de números imaginarios y complejos. + D_ soporta números complejos como ciudadanos de primera clase. Soporta + forma literal de números imaginarios y complejos. - Ejemplo:: + Ejemplo:: - ifloat im = 5.0i; - float re = 1.0; - cfloat c = re + im; // c == 1.0 + 5.0i - -.. [#1stclasscity] Por ciudadano de primera clase se entiende que se - trata de un tipo soportado por completo por el lenguaje, disponiendo de - expresiones literales anónimas, pudiendo ser almacenados en variables, - estructuras de datos, teniendo una identidad intrínseca, más allá - de un nombre dado, etc. En realidad los arreglos asociativos no pueden - ser expresados como literales anónimos pero sí tienen una sintaxis - especial soportada directamente por el lenguaje. + ifloat im = 5.0i; + float re = 1.0; + cfloat c = re + im; // c == 1.0 + 5.0i @@ -706,340 +694,342 @@ herramientas para soportar este paradigma de forma confiable. Entre las características más salientes se encuentran: 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]_. - - D_ además soporta tipos de retorno covariantes para funciones virtuales. - Esto significa que una función sobreescrita por una clase derivada puede - retornar un tipo que sea derivado del tipo retornado por la función - original sobreescrita. - - Ejemplo:: - - class A { } - class B : A { } - - class Foo { - A test() { return null; } - } + 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]_. + + .. [#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. + + D_ además soporta tipos de retorno covariantes para funciones virtuales. + Esto significa que una función sobreescrita por una clase derivada puede + retornar un tipo que sea derivado del tipo retornado por la función + original sobreescrita. + + Ejemplo:: + + class A { } + class B : A { } + + class Foo { + A test() { return null; } + } - class Bar : Foo { - B test() { return null; } // sobreescribe y es covariante con Foo.test() - } + class Bar : Foo { + B test() { return null; } // sobreescribe y es covariante con Foo.test() + } - Más información en http://www.digitalmars.com/d/1.0/function.html + Más información en http://www.digitalmars.com/d/1.0/function.html 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. + 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. Sobrecarga de operadores: - la sobrecarga de operadores permite que un objeto tenga una sintaxis - similar a un tipo de dato nativo. Esto es muy importante además para la - programación genérica. + la sobrecarga de operadores permite que un objeto tenga una sintaxis + similar a un tipo de dato nativo. Esto es muy importante además para la + programación genérica. Clases anidadas: - al igual que C (con respecto a ``struct``) y C++, pueden anidarse clases - dentro de clases. D_ sin embargo provee la posibilidad de acceder - a atributos de la instancia exterior desde la anidada. - - Ejemplo:: - - class Exterior { - int m; - class Anidada { - int foo() { - return m; // ok, puede acceder a un miembro de Exterior - } + al igual que C (con respecto a ``struct``) y C++, pueden anidarse clases + dentro de clases. D_ sin embargo provee la posibilidad de acceder + a atributos de la instancia exterior desde la anidada. + + Ejemplo:: + + class Exterior { + int m; + class Anidada { + int foo() { + return m; // ok, puede acceder a un miembro de 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:: - - class Exterior { - int m; - static int n; - static class Anidada { - int foo() { - //return m; // error, miembro de Exterior - return n; // ok, miembro estático de 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:: + + class Exterior { + int m; + static int n; + static class Anidada { + int foo() { + //return m; // error, miembro de Exterior + return n; // ok, miembro estático de Exterior + } + } } - } Propiedades (*properties*): - en D_ se refiere a funciones miembro que pueden ser tratadas - sintácticamente como campos de esa clase/estructura. - - Ejemplo:: - - class Foo { - int data() { return _data; } // propiedad de lectura - int data(int value) { return _data = value; } // de escritura - private int _data; - } - Foo f = new Foo; - f.data = 1; // llama a f.data(1) - int i = f.data; // llama a f.data() - - Además tipos nativos, clases, estructuras y expresiones tienen - *properties* predefinidos, por ejemplo: - - ``sizeof``: - tamaño ocupado en memoria (ejemplo: ``int.sizeof`` -> 4). - - ``init``: - valor de inicialización por omisión (ejemplo: ``float.init`` -> *NaN* - [#dnan]_). - - ``stringof``: - representación textual del tipo (ejemplo: ``(1+2).stringof`` -> ``"1 - + 2"``). - - ``mangleof``: - representación textual del tipo *mutilado* [#dmangle]_. - - ``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. - - Más información sobre *properties* de clases en - http://www.digitalmars.com/d/1.0/property.html#classproperties - y sobre *properties* predefinidos en - http://www.digitalmars.com/d/1.0/property.html - - -.. [#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. -.. [#dnan] Del inglés *Not A Number*, es un valor especial que indica que - estamos ante un valor inválido. -.. [#dmangle] *Name mangling* es el nombre dado comunmente a una técnica - necesaria para poder sobrecargar nombres de símbolos. Consiste en - codificar los nombres de las funciones tomando como entrada el nombre de - la función y la cantidad y tipo de parámetros, asegurando que dos - funciones con el mismo nombre pero distintos parámetros (sobrecargada) - tengan nombres distintos. + en D_ se refiere a funciones miembro que pueden ser tratadas + sintácticamente como campos de esa clase/estructura. + + Ejemplo:: + + class Foo { + int data() { return _data; } // propiedad de lectura + int data(int value) { return _data = value; } // de escritura + private int _data; + } + Foo f = new Foo; + f.data = 1; // llama a f.data(1) + int i = f.data; // llama a f.data() + + Además tipos nativos, clases, estructuras y expresiones tienen + *properties* predefinidos, por ejemplo: + + ``sizeof``: + tamaño ocupado en memoria (ejemplo: ``int.sizeof`` -> 4). + + ``init``: + valor de inicialización por omisión (ejemplo: ``float.init`` -> *NaN* + [#dnan]_). + + .. [#dnan] Del inglés *Not A Number*, es un valor especial que indica que + estamos ante un valor inválido. + + ``stringof``: + representación textual del tipo (ejemplo: ``(1+2).stringof`` -> ``"1 + + 2"``). + + ``mangleof``: + representación textual del tipo *mutilado* [#dmangle]_. + + .. [#dmangle] *Name mangling* es el nombre dado comunmente a una técnica + necesaria para poder sobrecargar nombres de símbolos. Consiste en + codificar los nombres de las funciones tomando como entrada el nombre de + la función y la cantidad y tipo de parámetros, asegurando que dos + funciones con el mismo nombre pero distintos parámetros (sobrecargada) + tengan nombres distintos. + + ``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. + + Más información sobre *properties* de clases en + http://www.digitalmars.com/d/1.0/property.html#classproperties y sobre + *properties* predefinidos en + http://www.digitalmars.com/d/1.0/property.html + 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 - silenciosamente sin ser detectados. + 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. + 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. - Ejemplo:: + Ejemplo:: - File f = open("archivo"); - assert (f.ok()); + File f = open("archivo"); + 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. - - 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): + 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): + + Pre y post condiciones: + Ejemplo:: + + double raiz_cuadrada(double x) + in { // pre-condiciones + assert (x >= 0.0); + } + out (resultado) { // post-condiciones + assert (resultado >= 0.0); + if (x < 1.0) + assert (resultado < x); + else if (x > 1.0) + assert (resultado > x); + else + assert (resultado == 1); + } + body { + // implementación + } + + 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``. + + Ejemplo:: + + class Fecha { + int dia; + int hora; + invariant() { + assert(1 <= dia && dia <= 31); + assert(0 <= hora && hora < 24); + } + } + + Más información en http://www.digitalmars.com/d/1.0/dbc.html - ure y post condiciones: - Ejemplo:: +Pruebas unitarias: + es posible incluir pequeñas pruebas unitarias en el lenguaje. Éstas son + ejecutadas (cuando no se compila en modo *release*) al comenzar el + programa, antes de que la función ``main()``. - double raiz_cuadrada(double x) - in { // pre-condiciones - assert (x >= 0.0); - } - out (resultado) { // post-condiciones - assert (resultado >= 0.0); - if (x < 1.0) - assert (resultado < x); - else if (x > 1.0) - assert (resultado > x); - else - assert (resultado == 1); - } - body { - // implementación - } + 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``. - - Ejemplo:: - - class Fecha { - int dia; - int hora; - invariant() { - assert(1 <= dia && dia <= 31); - assert(0 <= hora && hora < 24); - } + unittest { + Fecha fecha; + fecha.dia = 5; + assert (fecha.dia == 5); + assert (fecha); } - Más información en http://www.digitalmars.com/d/1.0/dbc.html +Orden de construcción estática: + 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. -Pruebas unitarias: - es posible incluir pequeñas pruebas unitarias en el lenguaje. Éstas son - ejecutadas (cuando no se compila en modo *release*) al comenzar el - programa, antes de que la función ``main()``. +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. - Ejemplo:: + Ejemplo:: - unittest { - Fecha fecha; - fecha.dia = 5; - assert (fecha.dia == 5); - assert (fecha); - } + 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) -Orden de construcción estática: - 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. +*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. -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. + Esta técnica es la base para desarrollar código seguro en cuanto + a excepciones (*exception-safe*) [SUTT99]_. - Ejemplo:: + 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. - 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) + Ejemplo:: -*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. - - 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 - 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. - - Ejemplo:: - - class Archivo { - this() { /* adquiere recurso */ } - ~this() { /* libera recurso */ } - } - void f() { - scope Archivo archivo = new Archivo; - // uso de archivo - } // en este punto se llama al destructor de archivo + class Archivo { + this() { /* adquiere recurso */ } + ~this() { /* libera recurso */ } + } + void f() { + scope Archivo archivo = new Archivo; + // uso de archivo + } // 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. - - Ejemplo:: - - int f(Lock lock) { - lock.lock(); - scope (exit) - lock.unlock(); // ejecutado siempre que salga de f() - auto trans = new Transaccion; - scope (success) - trans.commit(); // ejecutado si sale con "return" - scope (failure) - trans.rollback(); // ejecutado si sale por una excepción - if (condicion) - throw Exception("error"); // ejecuta 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() - } - - 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*. + 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() + auto trans = new Transaccion; + scope (success) + trans.commit(); // ejecutado si sale con "return" + scope (failure) + trans.rollback(); // ejecutado si sale por una excepción + if (condicion) + throw Exception("error"); // ejecuta 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() + } + + 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:: - - class Foo { - synchronized void bar() { /* cuerpo */ } - } - - Es equivalente a:: - - class Foo { - void bar() { - synchronized (this) { /* cuerpo */ } + 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:: + + class Foo { + synchronized void bar() { /* cuerpo */ } + } + + Es equivalente a:: + + class Foo { + void bar() { + synchronized (this) { /* cuerpo */ } + } } - } Compiladores @@ -1050,53 +1040,53 @@ y LDC_. 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. -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. +.. [#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 + representación intermedia que luego el *back-end* convierte a código de + máquina. + +.. [#backend] El *back-end* es la parte del compilador encargada de convertir + 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. __ 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_. -.. [#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 - representación intermedia que luego el *back-end* convierte a código de - máquina. -.. [#backend] El *back-end* es la parte del compilador encargada de - convertir la representación intermedia generada por el *front-end* - a código de máquina. - .. include:: links.rst -.. vim: set ts=2 sts=2 sw=2 et tw=75 : +.. vim: set ts=3 sts=3 sw=3 et tw=78 :