2 .. Introducción y breve reseña del lenguaje de programación D. También
3 se presentan las necesidades particulares de D con respecto al
4 recolector de basura y su estado actual.
5 ESTADO: TERMINADO, CORREGIDO
12 El lenguaje de programación D
13 ============================================================================
17 ----------------------------------------------------------------------------
19 D_ es un lenguaje de programación relativamente joven. Nació en 1999 y el
20 2 de enero de 2007 salió su `versión 1.0`__. Poco tiempo después se continúo
21 el desarrollo del lenguaje en la `versión 2.0`__, que pasó a ser considerada
22 estable aproximadamente en junio de 2010 con el lanzamiento del libro "The
23 D Programming Language" [ALX10]_, pero aún es un trabajo en progreso.
28 El lenguaje fue diseñado e implementado por `Walter Bright`_, desarrollador
29 principal de Zortech C++, uno de los primeros compiladores de C++ que
30 compilaba a código nativo, y está fuertemente influenciado por éste. Sin
31 embargo toma muchos conceptos de otros lenguajes de más alto nivel, como Java_
32 o incluso lenguajes dinámicos como Perl_, Python_ y Ruby_.
34 El origen del lenguaje está plasmado en su sitio web, en donde se cita
37 It seems to me that most of the "new" programming languages fall into one
38 of two categories: Those from academia with radical new paradigms and those
39 from large corporations with a focus on RAD and the web. Maybe it's time
40 for a new language born out of practical experience implementing compilers.
42 Esto podría traducirse como:
44 Parece que la mayoría de los lenguajes de programación "nuevos" caen en
45 2 categorías: aquellos académicos con nuevos paradigmas radicales
46 y aquellos de grandes corporaciones con el foco en el desarrollo rápido
47 y web. Tal vez es hora de que nazca un nuevo lenguaje de la experiencia
48 práctica implementando compiladores.
50 La versión 1.0 fue más bien una etiqueta arbitraria que un indicador real de
51 estabilidad y completitud. Luego de liberarse se siguieron agregando nuevas
52 características al lenguaje hasta que se empezó el desarrollo en paralelo de
53 la versión 2.0 al introducirse el concepto de inmutabilidad y funciones
54 *puras* [#dpure]_ (a mediados de 2007).
56 .. [#dpure] Por funciones *puras* en D_ se entiende que no tienen efectos
57 colaterales. Es decir, una función pura siempre que se llame con la misma
58 entrada producirá el mismo resultado. Esto es análogo a como funcionan los
59 lenguajes funcionales en general, abriendo la puerta a la programación de
60 estilo funcional en D_.
62 A partir de este momento la versión 1.0 quedó *teóricamente* congelada,
63 introduciendo solo cambios que arreglen errores (*bug fixes*), agregando
64 nuevas características solamente en la versión 2.0 del lenguaje. La realidad
65 es que se hicieron cambios incompatibles a la versión 1.0 del lenguaje en
66 reiteradas ocasiones, pero se fue tendiendo a cada vez introducir menos
67 cambios incompatibles. Sin embargo al día de hoy el compilador de referencia
68 sigue teniendo algunas características presentes en la especificación del
69 lenguaje sin implementar, por lo que todavía no hay una implementación
70 completa de la versión 1.0 del lenguaje.
72 El lenguaje ha sido, hasta el desarrollo de la versión 2.0 al menos, un
73 esfuerzo unipersonal de `Walter Bright`_, dados sus problemas a la hora de
74 delegar o aceptar contribuciones. Esto motivó a la comunidad de usuarios de D_
75 a crear bibliotecas base alternativas a la estándar (llamada Phobos_) en las
76 cuales se pudiera trabajar sin las trabas impuestas por el autor del lenguaje.
78 En este contexto nacen primero Mango_ y luego Ares_. Mango_ fue creada por
79 Kris Macleod Bell a principios de 2004 como una biblioteca que provee
80 servicios básicos de entrada/salida (o *I/O* de *input/output* en inglés) de
81 alto rendimiento. Siendo estos servicios algo básico lo más natural hubiera
82 sido que se encuentren en la biblioteca estándar de D_ pero por las
83 dificultades para contribuir a ésta, se desarrolla como una biblioteca
84 separada. A mediados de 2004 Sean Kelly crea Ares_ , con las mismas
85 motivaciones pero con la intención de crear una biblioteca base (conocida en
86 inglés como *runtime*) que incluye los servicios básicos que necesita el
87 lenguaje (información de tipos, manejo de excepciones e hilos, creación
88 y manipulación de objetos, recolector de basura, etc.). Al poco tiempo de
89 liberarse Ares_, Mango_ empieza a utilizarla como biblioteca base.
91 Para comienzos de 2006, se empieza a trabajar en la combinación de ambas
92 bibliotecas para lograr una biblioteca estándar alternativa con un alto grado
93 de cohesión. Finalmente a principios de 2007, coincidiendo por casualidad con
94 la aparición de `D 1.0`_, se anuncia el resultado de este combinación bajo el
95 nombre de Tango_, proveyendo una alternativa completa y madura a la biblioteca
96 estándar de D_ Phobos_. A principios de 2008 los principales desarrolladores
97 de Tango_ (Kris Bell, Sean Kelly, Lars Ivar Igesund y Michael Parker) publican
98 el libro llamado `Learn to Tango with D`_ [BKIP08]_.
100 Esto por un lado fue un gran avance porque dio un impulso muy considerable al
101 lenguaje pero por otro un gran retroceso, porque todavía al día de hoy `D
102 1.0`_ tiene dos bibliotecas base, una estándar pero de peor calidad, menos
103 mantenida y usada; y una alternativa de mayor calidad y apertura a la
104 comunidad (pero no estándar). El peor problema es que ambas son
105 **incompatibles**, por lo que un programa hecho con Tango_ no funciona con
106 Phobos_ y viceversa (a menos que el programador haya invertido una cantidad de
107 tiempo considerable en asegurarse que funcione con ambas).
109 Esto hace que la compatibilidad de programas y bibliotecas esté muy
110 fragmentada entre las dos bibliotecas base. Si bien no parece que vaya a haber
111 solución alguna a este problema para `D 1.0`_, `D 2.0`_ va en camino
112 a solucionar este problema ya que utiliza DRuntime_, un nuevo intento de Sean
113 Kelly por proveer una biblioteca *runtime* bien organizada y mantenida, que es
114 una adaptación de la biblioteca *runtime* de Tango_ a `D 2.0`_. Sin embargo
115 Tango_ no fue adaptada a `D 2.0`_ todavía, y no hay muchas perspectivas de que
116 sea portada en algún momento, por un lado porque en general la comunidad sigue
117 fragmentada entre muchos usuarios de `D 1.0`_ que no están contentos con los
118 cambios introducidos en `D 2.0`_, en su mayoría usuarios de Tango_, y que no
119 planean migrar a esa versión; y por otro porque el desarrollo de Phobos_ 2.0
120 se ha abierto mucho y tiene muchos colaboradores, por lo tanto la mayor parte
121 de la gente que utiliza `D 2.0`_ está contenta con el estado de Phobos_ 2.0.
125 ----------------------------------------------------------------------------
127 D_ es un lenguaje de programación con sintaxis tipo C, multi-paradigma,
128 compilado, con *tipado* fuerte y estático, buenas capacidades tanto de
129 programación de bajo nivel (*system programming*) como de alto nivel; además
130 es compatible de forma binaria con C (se puede enlazar código objeto C con
131 código objeto D). Con estas características, D_ logra llenar un vacío
132 importante que hay entre lo lenguajes de alto bajo nivel y los de alto nivel
133 [BKIP08]_. Si bien tiene herramientas de muy bajo nivel, que por lo tanto son
134 muy propensas a errores, da una infinidad de mecanismos para evitar el uso de
135 estas herramientas a menos que sea realmente necesario. Además pone mucho
136 énfasis en la programación confiable, para lo cual provee muchos mecanismos
137 para detectar errores en los programas de forma temprana.
139 Si puede pensarse en C++ como un "mejor C", podría decirse que D_ es un "mejor
140 C++", ya que el objetivo del lenguaje es muy similar a C++, pero implementa
141 muchas características que jamás pudieron entrar en el estándar de C++ y lo
142 hace de una forma mucho más limpia, ya que no debe lidiar con problemas de
143 compatibilidad hacia atrás, y cuenta con la experiencia del camino recorrido
144 por C++, pudiendo extraer de él los mejores conceptos pero evitando sus
147 Una gran diferencia con C++ es que el análisis sintáctico (*parsing*) se puede
148 realizar sin ningún tipo de análisis semántico, dado que a diferencia de éstos
149 su gramática es libre de contexto (*context-free grammar*). Esto acelera
150 y simplifica considerablemente el proceso de compilación [WBB10]_ [DWOV]_.
152 Otra gran diferencia es que D_ decide incluir recolección de basura como parte
153 del lenguaje, mientras que en el comité de estandarización de C++ nunca se
154 llegó a un consenso para su incorporación.
157 Características del lenguaje
158 ----------------------------------------------------------------------------
160 A continuación se enumeran las principales características de D_, agrupadas
161 por unidades funcionales o paradigmas que soporta [DWLR]_:
167 Programación genérica y meta-programación
168 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
170 La programación genérica se trata de la capacidad de poder desarrollar
171 algoritmos y estructuras independientes de los tipos que manipulan (pero de
172 forma segura o *type-safe*). Esto fue muy popularizado por C++ gracias a su
173 soporte de plantillas (*templates*) y luego otros lenguajes como Java_ y `C#`_
174 lo siguieron. Sin embargo otros lenguajes proveen formas más avanzadas de
175 programación genérica, gracias a sistemas de tipos más complejos (como
178 La meta-programación se refiere en general a la capacidad de un lenguaje para
179 permitir generar código dentro del mismo programa de forma automática. Esto
180 permite evitar duplicación de código y fue también muy popularizado por el
181 soporte de *templates* de C++, aunque muchos otros lenguajes tienen mejor
182 soporte de meta-programación, en especial los lenguajes dinámicos (como
185 D_ provee las siguientes herramientas para realizar programación genérica
188 ``if`` estático (``static if``)
189 Esta construcción es similar a la directiva del preprocesador de C/C++
190 ``#if``, pero a diferencia de éste, el ``static if`` de D_ tiene acceso
191 a todos los símbolos del compilador (constantes, tipos, variables, etc)
196 static if ((void*).sizeof == 4)
197 pragma(msg, "32 bits");
199 Inferencia de tipos básica implícita y explícita (mediante ``typeof``)
200 Si no se especifica un tipo al declarar una variable, se infiere a partir
201 del tipo de su valor de inicialización [DWIN]_.
205 static i = 5; // i es int
206 const d = 6.0; // d es double
207 auto s = "hola"; // s es string (que es un alias de char[])
209 Mediante el uso de ``typeof`` se puede solicitar el tipo de una expresión
214 typeof(5 + 6.0) d; // d es double
216 Iteración sobre colecciones (``foreach``)
217 Cualquier tipo de colección (arreglos estáticos y dinámicos, arreglos
218 asociativos, clases, estructuras o delegados) puede ser iterada mediante la
219 sentencia ``foreach`` [DWFE]_.
223 int[] a = [ 1, 2, 3 ];
229 Tanto clases como funciones pueden ser generalizadas. Esto permite desarrollar
230 algoritmos genéricos sin importar el tipo de los datos de entrada, siempre
231 y cuando todos los tipos tengan una *interfaz* común. Esto también es
232 conocido como *polimorfismo en tiempo de compilación*, y es la forma más
233 básica de programación genérica [DWTP]_.
237 T sumar(T)(T x, T y) { return x + y; }
238 auto i = sumar!(int)(5, 6); // i == 11
239 auto f = sumar!(float)(5, 6); // j == 11.0f
241 Además se pueden definir bloques de declaraciones generalizadas (esto no
242 es posible en C++), permitiendo instanciar dicho bloque con parámetros
243 particulares. Esto sirve como un mecanismo para la reutilización de código,
244 ya que puede incluirse un mismo bloque en distintos lugares (por ejemplo
245 clases). Un bloque generalizado puede verse como una especie de módulo.
249 template bloque(T, U) {
254 bloque!(int, float).x = 5;
255 float f = bloque!(int, float).foo(7);
257 La utilidad más prominente de los bloques generalizados se da al
258 acompañarse de *mixins*.
260 Además las *templates* de D_ tienen las siguientes características
263 Instanciación implícita de funciones generalizadas
264 El lenguaje es capaz de deducir los parámetros siempre que no hayan
269 auto i = sumar(5, 6); // i == 11
270 auto f = sumar(5.0f, 6.0f); // f == 11.0f
272 Especialización explícita y parcial de *templates*
273 La especialización de *templates* consiste, al igual que en C++, en
274 proveer una implementación especializada para un tipo de dato (o valor)
275 de los parámetros. Especialización parcial se refiere a la capacidad
276 de especializar un parámetro a través de un subtipo. Por ejemplo, se
277 puede especializar un *template* para cualquier tipo de puntero, o para
278 cualquier tipo de arreglo dinámico, sin necesidad de especificar el tipo
279 al que apunta dicho puntero o el tipo almacenado por el arreglo.
281 Ejemplo de especialización::
283 T sumar(T: int)(T x, T y) { return x + y + 1; }
284 auto i = sumar(5, 6); // i == 12
285 auto f = sumar(5.0f, 6.0f) // f == 11.0f
287 Ejemplo de especialización parcial::
289 T sumar(T: T*)(T x, T y) { return *x + *y; }
291 auto i = sumar(&x, &y); // i == 11
292 float v = 5.0f, w = 6.0f;
293 auto f = sumar(&v, &w); // f == 11.0f
295 Tipos, valores (incluyendo *strings*) y *templates* como parámetros
296 Este es otro bloque de construcción importantísimo para la programación
297 genérica en D, ya que combinando *templates* que toman *strings* como
298 parámetro en combinación con *string mixins* pueden hacerse toda clase
303 template hash(string s, uint so_far=0) {
304 static if (s.length == 0)
307 const hash = hash!(s[1 .. length], so_far * 11 + s[0]);
309 string s = hash!("hola"); // calculado en tiempo de compilación
311 Cantidad de parámetros variables para *templates*
312 Esta característica permite implementar tuplas y otros algoritmos que
313 inherentemente deben tomar una cantidad variable de parámetros en tiempo
318 double sumar(T...)(T t) {
324 double d = sumar(1, 2.0, 3.0f, 4l); // d == 10.0
326 *CTFE* (*compile-time function execution*)
327 Si una función cumple ciertas reglas básicas (como por ejemplo no tener
328 efectos colaterales) puede ser ejecutada en tiempo de compilación en vez de
329 tiempo de ejecución. Esto permite hacer algunos cálculos que no cambian de
330 ejecución en ejecución al momento de compilar, mejorando el rendimiento
331 o permitiendo formas avanzadas de meta-programación. Esta característica se
332 vuelve particularmente útil al combinarse con *string mixins* [DWCF]_.
336 int factorial(int n) {
340 return n * factorial(n - 1);
342 static int x = factorial(5); // calculado en tiempo de compilación
343 int x = factorial(5); // calculado en tiempo de ejecución
345 Esta característica es muy importante para evitar la duplicación de código.
347 *Mixins*, incluyendo *string mixins*
348 La palabra *mixin* tiene significados distintos en varios lenguajes de
349 programación. En D_ *mixin* significa tomar una secuencia arbitraria de
350 declaraciones e insertarla en el contexto (*scope*) actual. Esto puede
351 realizarse a nivel global, en clases, estructuras o funciones. Esto sirve
352 como un mecanismo para evitar duplicación de código que puede ser
353 introducida por la falta de herencia múltiple [DWMT]_.
358 mixin bloque!(int, float);
362 float f = a.foo(a.x);
365 mixin bloque!(long, double);
369 double d = a.foo(a.x);
371 *String mixin* se refiere a la capacidad de *incrustar* un *string* que
372 contenga un fragmento de código en un programa como si este fragmento
373 hubiera sido escrito en el código fuente directamente por el programador.
374 Esto permite hacer manipulaciones arbitrariamente complejas en combinación
375 con funciones ejecutadas en tiempo de compilación [DWME]_ [DWMX]_.
379 string generar_sumar(string var_x, string var_y) {
380 return "return " ~ var_x ~ " + " ~ var_y ~ ";";
383 int sumar(int a, int b) {
384 mixin(generar_sumar!("a", b"));
388 Las *expresiones ``is``* permiten la compilación condicional basada en las
389 características de un tipo [DWIE]_.
394 static if (is(T == class))
400 Esto provee además una forma simple de reflexión en tiempo de compilación.
406 Programación de bajo nivel (*system programming*)
407 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
409 Por programación de bajo nivel nos referimos a la capacidad de un lenguaje de
410 manipular el hardware directamente, o al menos la memoria. C es probablemente
411 el lenguaje de bajo nivel más popular, seguido por C++.
413 D_ presenta muchas características de bajo nivel:
415 Compila a código de máquina nativo
416 Los programas generados por D_ no son interpretados ni necesitan una
417 máquina virtual como otros lenguajes de más alto nivel como Java_, `C#`_,
418 Python_, etc [DWOV]_.
421 Provee acceso directo al *hardware* y la posibilidad de utilizar cualquier
422 característica de éste que no esté disponible en el lenguaje.
424 Una ventaja sobre C y C++ es que el lenguaje *assembly* utilizado dentro de
425 D_ está especificado, por lo que se puede mantener la portabilidad entre
426 compiladores incluso cuando se utiliza *assembly* (mientras que no se
427 cambie de arquitectura, por supuesto) [DWIA]_.
430 Al igual que C y C++, D_ provee la flexibilidad del uso de ``goto``
434 Soporta todos los tipos de C y es ABI [#abi]_ compatible con éste. Esto
435 permite enlazar archivos objeto estándar de C y D_ en un mismo programa.
436 Además permite interoperar con C a través de ``extern (C)`` [DWCC]_.
438 .. [#abi] Interfaz de Aplicación Binaria (del inglés *Application Binary
443 extern (C) printf(const char* format, ...);
444 printf("3 + 5 == %d\n", 3 + 5); // llama al printf de C
446 Manejo de memoria explícito
447 Permite asignar estructuras en el *stack* o en el *heap*, haciendo uso de
448 los servicios del sistema operativo o la biblioteca estándar de C [DWMM]_.
450 Objetos y arreglos *livianos*
451 Por objetos *livianos* se entiende no-polimórficos. Es decir, un
452 agrupamiento de variables análogo al ``struct`` de C, sin tabla virtual ni
453 otro tipo de *overhead*. Los arreglos *livianos* son arreglos estáticos
454 como en C, cuyo tamaño es fijo, también sin ningún tipo de *overhead* como
455 C. Además puede asignarse un arreglo dinámicamente usando ``malloc()``
456 y utilizar el operador ``[]`` para accederlo [DWST]_ [DWCL]_.
458 Esto también permite interoperar con C, ya que pueden definirse ``structs``
459 y arreglos que pueden ser intercambiados con dicho lenguaje sin problemas.
468 void* malloc(size_t);
469 size_t strlen(const char *);
470 int gettimeofday(timeval *, void *);
472 char* s = cast(char*) malloc(2);
475 size_t l = strlen(s); // l == 1
477 gettimeofday(&tv, null);
480 La :ref:`d_generic` permite realizar muchas optimizaciones ya que se
481 resuelve en tiempo de compilación y por lo tanto aumenta el rendimiento en
482 la ejecución [DWTP]_.
484 Número de punto flotante de 80 bits
485 El tipo ``real`` de D_ tiene precisión de 80 bits si la plataforma lo
486 soporta (por ejemplo en i386) [DWTY]_.
488 Control de alineación de miembros de una estructura
489 Mediante ``align`` se puede especificar la alineación a tener en una
495 struct paquete_de_red {
499 // paquete_de_red.sizeof == 3
505 Programación de alto nivel
506 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
508 Programación de alto nivel se refiere a construcciones más avanzadas que una
509 sentencia para iterar; expresiones con una semántica más ricas que proveen de
510 mayor expresividad al programador o le permiten focalizarse de mejora manera
511 en los algoritmos independizándose del *hardware* o de como funciona una
512 computadora. Es exactamente el opuesto a :ref:`d_low_level`.
514 En general estas características tienen como efecto secundario una mejora de la
515 productividad de los programadores. D_ adopta herramientas de muchos lenguajes
516 de alto nivel, como Java_ y Python_, por ejemplo:
518 Manejo automático de memoria
519 Al igual que C/C++ y prácticamente cualquier lenguaje imperativo maneja
520 automáticamente el *stack*, pero a diferencia de la mayoría de los
521 lenguajes de bajo nivel, D_ permite manejar el *heap* de manera automática
522 también a través de un *recolector de basura* [DWGC]_.
524 Sistema de paquetes y módulos (similar a Java_ o Python_)
525 Un módulo es una unidad que agrupa clases, funciones y cualquier otra
526 construcción de lenguaje. Un paquete es una agrupación de módulos. D_
527 asocia un módulo a un archivo fuente (y un archivo objeto cuando éste es
528 compilado) y un paquete a un directorio. A diferencia de C/C++ no necesita
529 de un preprocesador para incluir declaraciones de otros *módulos* (en C/C++
530 no existe el concepto de módulo, solo de unidades de compilación) [DWMO]_.
551 f(); // ejecuta b.f()
553 Funciones y delegados
554 Las funciones pueden ser sobrecargadas (funciones con el mismo nombre pero
555 distinta cantidad o tipo de parámetros), pueden especificarse argumentos de
556 entrada, salida o entrada/salida, argumentos por omisión o argumentos
557 evaluados de forma perezosa (*lazy*). Además pueden tener una cantidad de
558 argumentos variables pero manteniendo información de tipos (más seguro que
561 Los *delegados* son punteros a función con un contexto asociado. Este
562 contexto puede ser un objeto (en cuyo caso la función es un método) o un
563 *stack frame* (en cuyo caso la función es una función anidada).
565 Además de esto los delegados son ciudadanos de primera clase
566 [#1stclasscity]_, disponiendo de forma literal (delegado anónimo), lo que
567 permite construcciones de alto nivel muy conveniente. Los argumentos
568 evaluados de forma perezosa no son más que un delegado que se ejecuta solo
571 .. [#1stclasscity] Por ciudadano de primera clase se entiende que se trata
572 de un tipo soportado por completo por el lenguaje, disponiendo de
573 expresiones literales anónimas, pudiendo ser almacenados en variables,
574 estructuras de datos, teniendo una identidad intrínseca, más allá de un
575 nombre dado, etc. En realidad los arreglos asociativos no pueden ser
576 expresados como literales anónimos pero sí tienen una sintaxis especial
577 soportada directamente por el lenguaje.
581 bool buscar(T[] arreglo, T item, bool delegate(T x, T y) igual) {
594 bool encontrado = buscar(personas, p,
595 (Persona x, Persona y) {
596 return x.nombre == y.nombre;
600 Arreglos *dinámicos* y arreglos asociativos
601 Los arreglos *dinámicos* son arreglos de longitud variable manejados
602 automáticamente por el lenguaje (análogos al ``std::vector`` de C++).
603 Soportan concatenación (a través del operador ``~``), rebanado o *slicing*
604 (a través del operador ``[x..y]``) y chequeo de límites (*bound checking*)
607 Los arreglos asociativos (también conocidos como *hashes* o diccionarios)
608 también son provistos por el lenguaje [DWAA]_.
610 Ambos son ciudadanos de primera clase, disponiendo de forma literal.
614 int[] primos = [ 2, 3, 5, 7, 11, 13, 17, 19 ];
615 primos ~= [ 23, 29 ];
616 auto menores_que_10 = primos[0..4]; // [ 2, 3, 5, 7 ]
618 agenda["Pepe"] = 5555_1234;
621 Al igual que los delegados y arreglos dinámicos y asociativos, los
622 *strings* son ciudadanos de primera clase, teniendo forma literal y siendo
623 codificados en UTF-8/16/32. Son un caso particular de arreglo dinámico y es
624 posible utilizarlos en sentencias ``switch``/``case`` [DWSR]_.
637 ``typedef`` y ``alias``
638 El primero define un nuevo tipo basado en otro. A diferencia de C/C++ el
639 tipo original no puede ser implícitamente convertido al tipo nuevo (excepto
640 valores literales), pero la conversión es válida en el otro sentido
641 (similar a los ``enum`` en C++). Por el contrario, ``alias`` es análogo al
642 ``typedef`` de C/C++ y simplemente es una forma de referirse al mismo tipo
643 con un nombre distinto [DWDC]_.
652 foo(i); // error, no compila
657 Documentación embebida
658 D_ provee un sistema de documentación embebida, análogo a lo que proveen
659 Java_ o Python_ en menor medida. Hay comentarios especiales del código que
660 pueden ser utilizados para documentarlo de forma tal que luego el
661 compilador pueda extraer esa información para generar un documento [DWDO]_.
664 D_ soporta números complejos como ciudadanos de primera clase. Soporta
665 forma literal de números imaginarios y complejos [DWTY]_.
671 cfloat c = re + im; // c == 1.0 + 5.0i
675 Programación orientada a objetos
676 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
678 La orientación a objetos es probablemente el paradigma más utilizado en la
679 actualidad a la hora de diseñar e implementar un programa. D_ provee muchas
680 herramientas para soportar este paradigma de forma confiable. Entre las
681 características más salientes se encuentran:
684 Objetos polimórficos como los de cualquier lenguaje con orientación real
685 a objetos. Estos objetos poseen una tabla virtual para despacho dinámico,
686 todos los métodos son virtuales a menos que se indique lo contrario
687 y tienen semántica de referencia [#drefsem]_. Estos objetos tienen un
688 *overhead* comparados a los objetos *livianos* pero aseguran una semántica
689 segura para trabajar con orientación a objetos, evitando problemas con los
690 que se enfrenta C++ (como *slicing* [#dslicing]_) debido a que permite
691 semántica por valor [#dvalsem]_ [DWCL]_.
693 .. [#drefsem] Semántica de referencia significa que el tipo es tratado como
694 si fuera un puntero. Nunca se hacen copias del objeto, siempre se pasa
696 .. [#dslicing] Este problema se da en C++ cuando se pasa una clase derivada
697 a una función que acepta una clase base por valor como parámetro. Al
698 realizarse una copia de la clase con el constructor de copia de la clase
699 base, se pierden (o *rebanan*) los atributos de la clase derivada, y la
700 información de tipos en tiempo de ejecución (*RTTI*).
701 .. [#dvalsem] Semántica de valor significa que el tipo es tratado como si
702 fuera un valor concreto. En general se pasa por valor y se hacen copias
703 a menos que se utilice explícitamente un puntero.
705 D_ además soporta tipos de retorno covariantes para funciones virtuales.
706 Esto significa que una función sobreescrita por una clase derivada puede
707 retornar un tipo que sea derivado del tipo retornado por la función
708 original sobreescrita [DWFU]_.
716 A test() { return null; }
720 B test() { return null; } // sobreescribe y es covariante con Foo.test()
724 D_ no soporta herencia múltiple pero sí interfaces. Una interfaz es
725 básicamente una tabla virtual, una definición de métodos virtuales que debe
726 proveer una clase. Las interfaces no proveen una implementación de dichos
727 métodos, ni pueden tener atributos. Esto simplifica mucho el lenguaje y no
728 se pierde flexibilidad porque puede conseguirse el mismo efecto de tener
729 herencia múltiple a través de interfaces y *mixins* para proveer una
730 implementación o atributos en común a varias clases que implementan la
731 misma interfaz [DWIF]_.
733 Sobrecarga de operadores
734 La sobrecarga de operadores permite que un objeto tenga una sintaxis
735 similar a un tipo de dato nativo. Esto es muy importante además para la
736 programación genérica [DWOO]_.
739 Al igual que C (con respecto a ``struct``) y C++, pueden anidarse clases
740 dentro de clases. D_ sin embargo provee la posibilidad de acceder
741 a atributos de la instancia exterior desde la anidada [DWNC]_.
749 return m; // ok, puede acceder a un miembro de Exterior
754 Esto tiene un pequeño *overhead* ya que la clase ``Anidada`` debe guardar
755 un puntero a la clase ``Exterior``. Si no se necesita este comportamiento
756 es posible evitar este *overhead* utilizando ``static``, en cuyo caso solo
757 puede acceder a atributos estáticos de la clase ``Exterior``.
764 static class Anidada {
766 //return m; // error, miembro de Exterior
767 return n; // ok, miembro estático de Exterior
773 Propiedades (*properties*)
774 En D_ se refiere a funciones miembro que pueden ser tratadas
775 sintácticamente como campos de esa clase/estructura [DWPR]_.
780 int data() { return _data; } // propiedad de lectura
781 int data(int value) { return _data = value; } // de escritura
785 f.data = 1; // llama a f.data(1)
786 int i = f.data; // llama a f.data()
788 Además tipos nativos, clases, estructuras y expresiones tienen
789 *properties* predefinidos, por ejemplo:
792 Tamaño ocupado en memoria (ejemplo: ``int.sizeof`` -> 4).
795 Valor de inicialización por omisión (ejemplo: ``float.init`` -> *NaN*
798 .. [#dnan] Del inglés *Not A Number*, es un valor especial que indica que
799 estamos ante un valor inválido.
802 Representación textual del símbolo o expresión (ejemplo:
803 ``(1+2).stringof`` -> ``"1 + 2"``).
806 Representación textual del tipo *mutilado* [#dmangle]_.
808 .. [#dmangle] *Name mangling* es el nombre dado comunmente a una técnica
809 necesaria para poder sobrecargar nombres de símbolos. Consiste en
810 codificar los nombres de las funciones tomando como entrada el nombre de
811 la función y la cantidad y tipo de parámetros, asegurando que dos
812 funciones con el mismo nombre pero distintos parámetros (sobrecargada)
813 tengan nombres distintos.
816 Alineación de una estructura o tipo.
818 Estos son solo los *properties* predefinidos para todos los tipos, pero hay
819 una cantidad considerable de *properties* extra para cada tipo.
821 Más información sobre *properties* de clases en
822 http://www.digitalmars.com/d/1.0/property.html#classproperties y sobre
823 *properties* predefinidos en
824 http://www.digitalmars.com/d/1.0/property.html
830 Programación confiable
831 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
833 Programación confiable se refiere a las capacidades o facilidades que provee
834 el lenguaje para evitar fallas de manera temprana (o la capacidad de evitar
835 que ciertas fallas puedan existir directamente). D_ presta particular atención
836 a esto y provee las siguientes herramientas:
839 D_ soporta excepciones de manera similar a Java_: provee ``try``, ``catch``
840 y ``finally``. Esto permite que los errores difícilmente pasen
841 silenciosamente sin ser detectados [DWEX]_.
844 Es una condición que debe cumplirse siempre en un programa, como un chequeo
845 de integridad. Esto es muy utilizado en C/C++, donde ``assert()`` es una
846 *macro* que solo se compila cuando la *macro* ``NDEBUG`` no está definida.
847 Esto permite eliminar los chequeos de integridad del programa, que pueden
848 ser costosos, para versiones que se suponen estables.
850 D_ lleva este concepto más allá y hace al ``assert`` parte del lenguaje
851 [DWCP]_. Si una verificación no se cumple, lanza una excepción. El
852 ``assert`` no es compilado cuando se utiliza una opción del compilador.
856 File f = open("archivo");
860 El diseño por contrato es un concepto introducido por el lenguaje Eiffel_
861 a mediados/finales de los '80. Se trata de incorporar en el lenguaje las
862 herramientas para poder aplicar verificaciones formales a las interfaces de
865 D_ implementa las siguientes formas de diseño por contrato (todas se
866 ejecutan siempre y cuando no se compile en modo *release*, de manera de no
867 sacrificar rendimiento cuando es necesario) [DWCP]_:
869 Pre y post condiciones
872 double raiz_cuadrada(double x)
873 in { // pre-condiciones
876 out (resultado) { // post-condiciones
877 assert (resultado >= 0.0);
879 assert (resultado < x);
881 assert (resultado > x);
883 assert (resultado == 1);
889 Invariantes de representación
890 La invariante de representación es un método de una clase o estructura
891 que es verificada cuando se completa su construcción, antes de la
892 destrucción, antes y después de ejecutar cualquier función miembro
893 pública y cuando se lo requiere de forma explícita utilizando
902 assert(1 <= dia && dia <= 31);
903 assert(0 <= hora && hora < 24);
908 Es posible incluir pequeñas pruebas unitarias en el lenguaje. Éstas son
909 ejecutadas (cuando no se compila en modo *release*) al comenzar el
910 programa, antes de que la función ``main()`` [DWUT]_.
917 assert (fecha.dia == 5);
921 Orden de construcción estática
922 A diferencia de C++, D_ garantiza el orden de inicialización de los
923 módulos. Si bien en C++ no hay módulos si no unidades de compilación, es
924 posible que se ejecute código antes del ``main()`` en C++, si hay, por
925 ejemplo, instancias globales con un constructor definido. C++ no garantiza
926 un orden de inicialización, lo que trae muchos problemas. En D_ se define
927 el orden de inicialización y es el mismo orden en que el usuario importa
930 Inicialización garantizada
931 Todas las variables son inicializadas por el lenguaje (a menos que el
932 usuario pida explícitamente que no lo sean) [DWTY]_ [DWVI]_. Siempre que
933 sea posible se elijen valores de inicialización que permitan saber al
934 programador que la variable no fue inicializada explícitamente, de manera
935 de poder detectar errores de manera temprana.
939 double d; // inicializado a NaN
940 int x; // inicializado a 0
941 Fecha f; // inicializado a null
942 byte[5] a; // inicializados todos los valores a 0
943 long l = void; // NO inicializado (explícitamente)
945 *RAII* (*Resource Adquisition Is Initialization*)
946 Es una técnica muy utilizada en C++ que consiste en reservar recursos por
947 medio de la construcción de un objeto y liberarlos cuando se libera éste.
948 Al llamarse al destructor de manera automática cuando se sale del *scope*,
949 se asegura que el recurso será liberado también.
951 Esta técnica es la base para desarrollar código seguro en cuanto
952 a excepciones (*exception-safe*) [SUTT99]_.
954 En D_ no es tan común utilizar *RAII* dada la existencia del recolector de
955 basura (en la mayoría de los casos el recurso a administrar es
956 sencillamente memoria). Sin embargo en los casos en donde es necesario,
957 puede utilizarse *RAII* mediante la utilización de la palabra reservada
958 ``scope``, que limita la vida de un objeto un bloque de código [DWES]_.
963 this() { /* adquiere recurso */ }
964 ~this() { /* libera recurso */ }
967 scope Archivo archivo = new Archivo;
969 } // en este punto se llama al destructor de archivo
971 Guardias de bloque (*scope guards*)
972 Además de poder limitar la vida de una instancia a un *scope*, es posible
973 especificar un bloque de código arbitrario a ejecutar al abandonar un
974 *scope*, ya sea cuando se sale del *scope* normalmente o por una falla
982 lock.unlock(); // ejecutado siempre que salga de f()
983 auto trans = new Transaccion;
985 trans.commit(); // ejecutado si sale con "return"
987 trans.rollback(); // ejecutado si sale por una excepción
989 throw Exception("error"); // lock.unlock() y trans.rollback()
990 else if (otra_condicion)
991 return 5; // lock.unlock() y trans.commit()
992 return 0; // lock.unlock() y trans.commit()
995 Esta es una nueva forma de poder escribir código *exception-safe*, aunque
996 el programador debe tener un poco más de cuidado de especificar las
997 acciones a ejecutar al finalizar el *scope*.
999 Primitivas de sincronización de hilos
1000 La programación multi-hilo está directamente soportada por el lenguaje,
1001 y se provee una primitiva de sincronización al igual que Java_. La palabra
1002 reservada ``synchronized`` puede aparecer como modificador de métodos (en
1003 cuyo caso se utiliza un *lock* por clase para sincronizar) o como una
1004 sentencia, en cuyo caso se crea un *lock* global por cada bloque
1005 ``synchronized`` a menos que se especifique sobre qué objeto realizar la
1006 sincronización [DWSY]_. Por ejemplo::
1009 synchronized void bar() { /* cuerpo */ }
1016 synchronized (this) { /* cuerpo */ }
1022 ----------------------------------------------------------------------------
1024 Hay, hasta el momento, 3 compiladores de D_ de buena calidad: DMD_, GDC_
1027 DMD_ es el compilador de referencia, escrito por `Walter Bright`_. El
1028 *front-end* [#frontend]_ de este compilador ha sido liberado bajo licencia
1029 Artistic_/GPL_ y es utilizado por los otros dos compiladores, por lo tanto en
1030 realidad hay solo un compilador disponible con 3 *back-ends* [#backend]_
1033 .. [#frontend] *Front-end* es la parte del compilador encargada de hacer el
1034 análisis léxico, sintáctico y semántico del código fuente, generando una
1035 representación intermedia que luego el *back-end* convierte a código de
1038 .. [#backend] El *back-end* es la parte del compilador encargada de convertir
1039 la representación intermedia generada por el *front-end* a código de
1042 Con `DMD 1.041`__ se publicó el código fuente completo del compilador, pero
1043 con una licencia muy restrictiva para uso personal, por lo que el único efecto
1044 logrado por esto es que la gente pueda mandar parches o correcciones del
1045 compilador pero no lo convierte en `Software Libre`_, siendo el único de los
1046 3 compiladores que no tiene esta característica.
1048 __ http://www.digitalmars.com/d/1.0/changelog.html#new1_041
1050 El compilador GDC_ es el *front-end* de DMD_ utilizando al compilador GCC_
1051 como *back-end*. Fue un muy buen compilador pero estuvo abandonado por casi
1052 tres años. A mediados de este año recibió un nuevo impulso y de a poco se está
1053 poniendo al día con los *front-ends* actuales de DMD_ 1.0 y 2.0, aunque la
1054 versión 2.0 viene bastante más rezagada y todavía no es una alternativa viable
1057 LDC_ sufrió una suerte similar, es un compilador joven que utiliza como
1058 *back-end* a LLVM_ (una infraestructura modera para construir compiladores),
1059 nacido a mediados de 2007 como un proyecto personal y privado de Tomas
1060 Lindquist Olsen, que estuvo trabajando de forma privada en el proyecto hasta
1061 mediados de 2008, momento en que decide publicar el código mediante una
1062 licencia libre. Para ese entonces el compilador era todavía inestable
1063 y faltaban implementar varias cosas, pero el estado era lo suficientemente
1064 bueno como para captar varios colaboradores muy capaces, como `Christian
1065 Kamm`_ y Frits Van Bommel que rápidamente se convirtieron en parte fundamental
1066 del proyecto. El primer *release* (0.9) de una versión relativamente completa
1067 y estable fue a principios de 2009 que fue seguido por la versión 0.9.1 que
1068 como puntos más salientes agregó soporte para x86-64 y assembly embebido. El
1069 compilador tuvo un crecimiento excepcional pero estuvo muy inactivo por algún
1070 tiempo y, si bien sigue siendo mantenido, en general los nuevos *front-end* de
1071 DMD_ llevan tiempo de integrar y no está al día con el *back-end* de LLVM_
1072 (por ejemplo desde que se actualizó para utilizar LLVM_ 2.7 que perdió la
1073 capacidad de generar símbolos de depuración).
1075 Además de estos compiladores hay varios otros experimentales, pero ninguno de
1076 ellos de calidad suficiente todavía. Por ejemplo hay un compilador
1077 experimental que emite *CIL* (*Common Intermediate Language*), el *bytecode*
1078 de `.NET`_, llamado DNet_. También hay un *front-end* escrito en D_, llamado
1081 Originalmente, dado que GDC_ estaba siendo mantenido y que LDC_ no existía,
1082 este trabajo iba a ser realizado utilizando GDC_ como compilador, dado que al
1083 ser `Software Libre`_ podía ser modificado de ser necesario. Pero finalmente,
1084 dada la poca confiabilidad que presenta la continuidad del desarrollo de tanto
1085 GDC_ como LDC_, y que el código de DMD_ está disponible en su totalidad
1086 (aunque no sea `Software Libre`_ por completo), se optó por utilizar este
1087 último, dado que es la implementación de referencia que fue más constantemente
1088 mantenida y desarrollada.
1091 .. include:: links.rst
1093 .. vim: set ts=3 sts=3 sw=3 et tw=78 spelllang=es :