X-Git-Url: https://git.llucax.com/z.facultad/75.00/informe.git/blobdiff_plain/b0956c037ae52da777b06705157486067755ec2c..881c40a0d92402f50fb43b1665179fbed979ff68:/source/d.rst diff --git a/source/d.rst b/source/d.rst index f916af0..426a800 100644 --- a/source/d.rst +++ b/source/d.rst @@ -1,11 +1,7 @@ -.. 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 +.. highlight:: d - -.. _ref_d: +.. _d_lang: El lenguaje de programación D ============================================================================ @@ -15,109 +11,108 @@ 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`__, que pasó a ser considerada +estable aproximadamente en junio de 2010 con el lanzamiento del libro "The +D Programming Language" [ALX10]_, pero aún es un trabajo en progreso. __ `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 compiladores de C++ que +compilaba a código nativo, y está fuertemente influenciado por éste. Sin +embargo toma muchos conceptos de otros lenguajes de más alto nivel, como Java_ +o incluso lenguajes dinámicos como Perl_, Python_ y Ruby_. -El origen del lenguaje está plasmado en su sitio web, en donde se cita: +El origen del lenguaje está plasmado en su sitio web, en donde se cita +[DWEB]_: - 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 +estabilidad y completitud. 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, abriendo 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*), agregando +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. 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`_ [BKIP08]_. + +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 dos bibliotecas base, una estándar pero de peor calidad, menos +mantenida y usada; 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 considerable en asegurarse 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 dos 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`_. Sin embargo +Tango_ no fue adaptada a `D 2.0`_ todavía, y no hay muchas perspectivas de que +sea portada en algún momento, por un lado porque en general la comunidad sigue +fragmentada entre muchos usuarios de `D 1.0`_ que no están contentos con los +cambios introducidos en `D 2.0`_, en su mayoría usuarios de Tango_, y que no +planean migrar a esa versión; y por otro porque el desarrollo de Phobos_ 2.0 +se ha abierto mucho y tiene muchos colaboradores, por lo tanto la mayor parte +de la gente que utiliza `D 2.0`_ está contenta con el estado de Phobos_ 2.0. Descripción general @@ -125,55 +120,43 @@ 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 +programación de bajo nivel (*system programming*) como de alto nivel; además +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: - -1. Análisis léxico. -2. Análisis sintáctico. -3. Análisis semántico. -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). - - -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. +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. + +Una gran diferencia con C++ es que el análisis sintáctico (*parsing*) se puede +realizar sin ningún tipo de análisis semántico, dado que a diferencia de éstos +su gramática es libre de contexto (*context-free grammar*). Esto acelera +y simplifica considerablemente el proceso de compilación [WBB10]_ [DWOV]_. + +Otra gran diferencia es que D_ decide incluir recolección de basura como parte +del lenguaje, mientras que en el comité de estandarización de C++ nunca se +llegó a un consenso para su incorporación. 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 funcionales o paradigmas que soporta [DWLR]_: + -.. _ref_d_generic: +.. _d_generic: Programación genérica y meta-programación ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -181,519 +164,507 @@ 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). +``if`` estático (``static if``) + Esta construcción es similar a la directiva del preprocesador de C/C++ + ``#if``, pero a diferencia de éste, el ``static if`` de D_ tiene acceso + a todos los símbolos del compilador (constantes, tipos, variables, etc) + [DWSI]_. + + Ejemplo:: + + static if ((void*).sizeof == 4) + pragma(msg, "32 bits"); + +Inferencia de tipos básica implícita y explícita (mediante ``typeof``) + Si no se especifica un tipo al declarar una variable, se infiere a partir + del tipo de su valor de inicialización [DWIN]_. - Ejemplo:: + Ejemplo:: - static if ((void*).sizeof == 4) - pragma(msg, "32 bits"); + 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/version.html#staticif + Mediante el uso de ``typeof`` se puede solicitar el tipo de una expresión + arbitraria [DWTO]_. -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. + Ejemplo:: - Ejemplo:: + typeof(5 + 6.0) d; // d es double - 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[]) +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`` [DWFE]_. - Más información en - http://www.digitalmars.com/d/1.0/declaration.html#AutoDeclaration + Ejemplo:: - Mediante el uso de ``typeof`` se puede solicitar el tipo de una expresión - arbitraria. + int[] a = [ 1, 2, 3 ]; + int total = 0; + foreach (i; a) + total += i; - Ejemplo:: +*Templates* + Tanto clases como 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 [DWTP]_. - typeof(5 + 6.0) d; // d es double + Ejemplo:: - Más información en http://www.digitalmars.com/d/1.0/declaration.html#typeof + 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 -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``. + 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:: + + template bloque(T, U) { + T x; + U foo(T y); + } + + bloque!(int, float).x = 5; + float f = bloque!(int, float).foo(7); + + La utilidad más prominente de los bloques generalizados se da al + acompañarse de *mixins*. + + Además las *templates* de D_ tienen las siguientes características + destacables: + + Instanciación implícita de funciones generalizadas + El lenguaje es capaz de deducir los parámetros siempre que no hayan + ambigüedades. + + Ejemplo:: + + 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. + + Ejemplo de especialización:: + + T sumar(T)(T x, T y) { return x + y; } + 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:: + + T sumar(T)(T x, T y) { return x + y; } + 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 + Este 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 = so_far; + else + const hash = hash!(s[1 .. length], so_far * 11 + s[0]); + } + string s = hash!("hola"); // calculado en tiempo de compilación + + Cantidad de parámetros variables para *templates* + Esta característica permite implementar tuplas y otros algoritmos que + inherentemente deben tomar una cantidad variable de parámetros en tiempo + de compilación. + + 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 + +*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 el rendimiento + o permitiendo formas avanzadas de meta-programación. Esta característica se + vuelve particularmente útil al combinarse con *string mixins* [DWCF]_. + + 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 - Ejemplo:: + Esta característica es muy importante para evitar la duplicación de código. - int[] a = [ 1, 2, 3 ]; - int total = 0; - foreach (i; a) - total += i; +*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 [DWMT]_. -*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. + Ejemplo:: - 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 [DWME]_ [DWMX]_. + + 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")); + } - 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 +Expresiones ``is`` + Las *expresiones ``is``* permiten la compilación condicional basada en las + características de un tipo [DWIE]_. - 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:: + T foo(T)(T x) { + static if (is(T == class)) + return new T; + else + return T.init; + } - template bloque(T, U) { - T x; - U foo(T y); - } + Esto provee además una forma simple de reflexión en tiempo de compilación. - 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*. - -Instanciación implícita de funciones parametrizadas: - el lenguaje es capaz de deducir los parámetros siempre que no hayan - ambigüedades - - Ejemplo:: - - 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. - - 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 - - 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 - -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 - -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. - - 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 - -*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. - -*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 - -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. - - 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. +Compila a código de máquina nativo + Los programas generados por D_ no son interpretados ni necesitan una + máquina virtual como otros lenguajes de más alto nivel como Java_, `C#`_, + Python_, etc [DWOV]_. -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. +*Assembly* empotrado + Provee 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) [DWIA]_. -``goto``: - al igual que C y C++, D_ provee la flexibilidad del uso de ``goto``. +``goto`` + Al igual que C y C++, D_ provee la flexibilidad del uso de ``goto`` + [DWGT]_. 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:: - - 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. - -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); - -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. - -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). - -Control de alineación de miembros de 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 - - -.. [#abi] Interfaz de Aplicación Binaria (del inglés *Application Binary - Interface*). - - -.. _ref_d_high_level: + 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)`` [DWCC]_. + + .. [#abi] Interfaz de Aplicación Binaria (del inglés *Application Binary + Interface*). + + 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 asignar estructuras en el *stack* o en el *heap*, haciendo uso de + los servicios del sistema operativo o la biblioteca estándar de C [DWMM]_. + +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 asignarse un arreglo dinámicamente usando ``malloc()`` + y utilizar el operador ``[]`` para accederlo [DWST]_ [DWCL]_. + + 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:`d_generic` permite realizar muchas optimizaciones ya que se + resuelve en tiempo de compilación y por lo tanto aumenta el rendimiento en + la ejecución [DWTP]_. + +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) [DWTY]_. + +Control de alineación de miembros de una estructura + Mediante ``align`` se puede especificar la alineación a tener en una + estructura [DWAL]_. + + Ejemplo:: + + align (1) + struct paquete_de_red { + char tipo; + short valor; + } + // paquete_de_red.sizeof == 3 + + + +.. _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 -independizándose del *hardware* o de como funciona una computadora. Es -exactamente el opuesto a :ref:`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: - -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*. - -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). - - Ejemplo: - - ``a.d``:: - - module a; - void f() {} - - ``b.d``:: - - module b; - void f() {} - - ``c.d``:: - - 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; - } - ); - -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 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. - - 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; - -*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``. - - Ejemplo:: - - string s = "árbol"; - - 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); - -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. - - 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. - - 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. +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 proveen de +mayor expresividad al programador o le permiten focalizarse de mejor 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 tienen 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 *recolector de basura* [DWGC]_. + +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) [DWMO]_. + + Ejemplo: + + ``a.d``:: + + module a; + void f() {} + + ``b.d``:: + + module b; + void f() {} + + ``c.d``:: + + 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++) [DWFU]_. + + 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, item)) + 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*) + [DWAR]_. + + Los arreglos asociativos (también conocidos como *hashes* o diccionarios) + también son provistos por el lenguaje [DWAA]_. + + Ambos son ciudadanos de primera clase, disponiendo de forma literal. + + 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; + +*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`` [DWSR]_. + + Ejemplo:: + + string s = "árbol"; + + 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 [DWDC]_. + + 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 proveen + 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 [DWDO]_. + +Números complejos + D_ soporta números complejos como ciudadanos de primera clase. Soporta + forma literal de números imaginarios y complejos [DWTY]_. + + Ejemplo:: + + ifloat im = 5.0i; + float re = 1.0; + cfloat c = re + im; // c == 1.0 + 5.0i @@ -705,341 +676,337 @@ actualidad a la hora de diseñar e implementar un programa. D_ provee muchas 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; } - } - - 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 - -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. - -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. - -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 - } +Objetos *pesados* + Objetos polimórficos como los de cualquier lenguaje con orientación real + 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]_ [DWCL]_. + + .. [#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 [DWFU]_. + + Ejemplo:: + + class A { } + class B : A { } + + class Foo { + A test() { return null; } } - } - - 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 - } + + class Bar : Foo { + B test() { return null; } // sobreescribe y es covariante con Foo.test() } - } - - -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. +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 [DWIF]_. + +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 [DWOO]_. + +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 [DWNC]_. + + Ejemplo:: + + class Exterior { + int m; + class Anidada { + int foo() { + return m; // ok, puede acceder a un miembro de Exterior + } + } + } -Programación confiable -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + 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 [DWPR]_. + + 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]_). -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: + .. [#dnan] Del inglés *Not A Number*, es un valor especial codificado según + IEEE 754-2008 [IEEE754]_ que indica que estamos ante un valor inválido. -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. + ``stringof`` + Representación textual del símbolo o expresión (ejemplo: + ``(1+2).stringof`` -> ``"1 + 2"``). -``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. + ``mangleof`` + Representación textual del tipo *mutilado* [#dmangle]_ [DWAB]_. - 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. + .. [#dmangle] *Name mangling* es el nombre dado comúnmente 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. - Ejemplo:: + ``alignof`` + Alineación de una estructura o tipo. - File f = open("archivo"); - assert (f.ok()); + Estos son solo los *properties* predefinidos para todos los tipos, pero hay + una cantidad considerable de *properties* extra para cada tipo. -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): - ure y post condiciones: - Ejemplo:: +.. _d_dbc: - double raiz_cuadrada(double x) - in { // pre-condiciones - assert (x >= 0.0); +Programación confiable +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Programación confiable se refiere a las capacidades o facilidades que provee +el lenguaje para evitar fallas de manera temprana (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 [DWEX]_. + +``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. + + D_ lleva este concepto más allá y hace al ``assert`` parte del lenguaje + [DWCP]_. 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:: + + 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 rendimiento cuando es necesario) [DWCP]_: + + 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); + } + } + +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()`` [DWUT]_. + + Ejemplo:: + + unittest { + Fecha fecha; + fecha.dia = 5; + assert (fecha.dia == 5); + assert (fecha); } - 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); + +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 [DWMO]_. + +Inicialización garantizada + Todas las variables son inicializadas por el lenguaje (a menos que el + usuario pida explícitamente que no lo sean) [DWTY]_ [DWVI]_. 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:: + + 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. + + 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 a un bloque de código [DWES]_. + + Ejemplo:: + + class Archivo { + this() { /* adquiere recurso */ } + ~this() { /* libera recurso */ } } - body { - // implementación + 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 + [DWES]_. + + 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"); // lock.unlock() y trans.rollback() + else if (otra_condicion) + return 5; // lock.unlock() y trans.commit() + return 0; // lock.unlock() y trans.commit() } - 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); - } + 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 [DWSY]_. Por ejemplo:: + + class Foo { + synchronized void bar() { /* cuerpo */ } } - Más información en http://www.digitalmars.com/d/1.0/dbc.html - -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()``. - - Ejemplo:: - - unittest { - Fecha fecha; - fecha.dia = 5; - assert (fecha.dia == 5); - assert (fecha); - } - -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. - -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:: - - 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. - - 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 - -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*. - -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 */ } + Es equivalente a:: + + class Foo { + void bar() { + synchronized (this) { /* cuerpo */ } + } } - } Compiladores @@ -1050,53 +1017,68 @@ 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. + +.. [#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. +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_ +como *back-end*. Fue un muy buen compilador pero estuvo abandonado por casi +tres años. A mediados de este año recibió un nuevo impulso y de a poco se está +poniendo al día con los *front-ends* actuales de DMD_ 1.0 y 2.0, aunque la +versión 2.0 viene bastante más rezagada y todavía no es una alternativa viable +a DMD_. + +LDC_ sufrió una suerte similar, es un compilador joven que utiliza como +*back-end* a LLVM_ (una infraestructura modera para construir compiladores), +nacido a mediados de 2007 como un proyecto personal y privado de Tomas +Lindquist Olsen, que estuvo trabajando de forma privada en el proyecto hasta +mediados de 2008, momento en que decide publicar el código mediante una +licencia libre. Para ese entonces el compilador era todavía inestable +y faltaban implementar varias cosas, pero el estado era lo suficientemente +bueno como para captar varios colaboradores muy capaces, como `Christian +Kamm`_ y Frits Van Bommel que rápidamente se convirtieron en parte fundamental +del proyecto. El primer *release* (0.9) de una versión relativamente completa +y estable fue a principios de 2009 que fue seguido por la versión 0.9.1 que +como puntos más salientes agregó soporte para x86-64 y assembly embebido. El +compilador tuvo un crecimiento excepcional pero estuvo muy inactivo por algún +tiempo y, si bien sigue siendo mantenido, en general los nuevos *front-end* de +DMD_ llevan tiempo de integrar y no está al día con el *back-end* de LLVM_ +(por ejemplo desde que se actualizó para utilizar LLVM_ 2.7 que perdió la +capacidad de generar símbolos de depuración). + +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 *front-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_. - - -.. [#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. +este trabajo iba a ser realizado utilizando GDC_ como compilador, dado que al +ser `Software Libre`_ podía ser modificado de ser necesario. Pero finalmente, +dada la poca confiabilidad que presenta la continuidad del desarrollo de tanto +GDC_ como LDC_, y que el código de DMD_ está disponible en su totalidad +(aunque no sea `Software Libre`_ por completo), se optó por utilizar este +último, dado que es la implementación de referencia que fue más constantemente +mantenida y desarrollada. .. 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 spelllang=es :