
.. highlight:: d

.. _d_lang:

El lenguaje de programación D
============================================================================


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`__, 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 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
[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.

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.

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, 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*), 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.

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
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
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`_ [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 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
----------------------------------------------------------------------------

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; 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.

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 funcionales o paradigmas que soporta [DWLR]_:



.. _d_generic:

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_).

D_ provee las siguientes herramientas para realizar programación genérica
y meta-programación:

``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::

      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[])

   Mediante el uso de ``typeof`` se puede solicitar el tipo de una expresión
   arbitraria [DWTO]_.

   Ejemplo::

      typeof(5 + 6.0) d; // d es double

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]_.

   Ejemplo::

      int[] a = [ 1, 2, 3 ];
      int total = 0;
      foreach (i; a)
         total += i;

*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]_.

   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

   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

   Esta característica es muy importante 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 [DWMT]_.

   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"));
      }

Expresiones ``is``
   Las *expresiones ``is``* permiten la compilación condicional basada en las
   características de un tipo [DWIE]_.

   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.



.. _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++.

D_ presenta muchas características de bajo nivel:

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]_.

*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) [DWIA]_.

``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)`` [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
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

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



Programación orientada a objetos
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

La orientación a objetos es probablemente el paradigma más utilizado en la
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 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; }
      }

      class Bar : Foo {
         B test() { return null; } // sobreescribe y es covariante con Foo.test()
      }

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
            }
         }
      }

   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]_).

   .. [#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.

   ``stringof``
      Representación textual del símbolo o expresión (ejemplo:
      ``(1+2).stringof`` -> ``"1 + 2"``).

   ``mangleof``
      Representación textual del tipo *mutilado* [#dmangle]_ [DWAB]_.

   .. [#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.

   ``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.



.. _d_dbc:

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);
      }

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 */ }
      }
      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()
      }

   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 */ }
      }

   Es equivalente a::

      class Foo {
         void bar() {
            synchronized (this) { /* cuerpo */ }
         }
      }


Compiladores
----------------------------------------------------------------------------

Hay, hasta el momento, 3 compiladores de D_ de buena calidad: DMD_, GDC_
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.

.. [#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 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. 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=3 sts=3 sw=3 et tw=78 spelllang=es :
