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 (A)
10 El lenguaje de programación D
11 ============================================================================
15 ----------------------------------------------------------------------------
17 D_ es un lenguaje de programación relativamente joven. Nació en 1999 y el
18 2 de enero de 2007 salió su `versión 1.0`__. Poco tiempo después se continúo
19 el desarrollo del lenguaje en la `versión 2.0`__, que pasó a ser considerada
20 estable aproximadamente en junio de 2010 con el lanzamiento del libro "The
21 D Programming Language" [ALX10]_, pero aún es un trabajo en progreso.
26 El lenguaje fue diseñado e implementado por `Walter Bright`_, desarrollador
27 principal de Zortech C++, uno de los primeros compiladores de C++ que
28 compilaba a código nativo, y está fuertemente influenciado por éste. Sin
29 embargo toma muchos conceptos de otros lenguajes de más alto nivel, como Java_
30 o incluso lenguajes dinámicos como Perl_, Python_ y Ruby_.
32 El origen del lenguaje está plasmado en su sitio web, en donde se cita:
34 It seems to me that most of the "new" programming languages fall into one
35 of two categories: Those from academia with radical new paradigms and those
36 from large corporations with a focus on RAD and the web. Maybe it's time
37 for a new language born out of practical experience implementing compilers.
39 Esto podría traducirse como:
41 Parece que la mayoría de los lenguajes de programación "nuevos" caen en
42 2 categorías: aquellos académicos con nuevos paradigmas radicales
43 y aquellos de grandes corporaciones con el foco en el desarrollo rápido
44 y web. Tal vez es hora de que nazca un nuevo lenguaje de la experiencia
45 práctica implementando compiladores.
47 La versión 1.0 fue más bien una etiqueta arbitraria que un indicador real de
48 estabilidad y completitud. Luego de liberarse se siguieron agregando nuevas
49 características al lenguaje hasta que se empezó el desarrollo en paralelo de
50 la versión 2.0 al introducirse el concepto de inmutabilidad y funciones
51 *puras* [#dpure]_ (a mediados de 2007).
53 .. [#dpure] Por funciones *puras* en D_ se entiende que no tienen efectos
54 colaterales. Es decir, una función pura siempre que se llame con la misma
55 entrada producirá el mismo resultado. Esto es análogo a como funcionan los
56 lenguajes funcionales en general, abriendo la puerta a la programación de
57 estilo funcional en D_.
59 A partir de este momento la versión 1.0 quedó *teóricamente* congelada,
60 introduciendo solo cambios que arreglen errores (*bug fixes*), agregando
61 nuevas características solamente en la versión 2.0 del lenguaje. La realidad
62 es que se hicieron cambios incompatibles a la versión 1.0 del lenguaje en
63 reiteradas ocasiones, pero se fue tendiendo a cada vez introducir menos
64 cambios incompatibles. Sin embargo al día de hoy el compilador de referencia
65 sigue teniendo algunas características presentes en la especificación del
66 lenguaje sin implementar, por lo que todavía no hay una implementación
67 completa de la versión 1.0 del lenguaje.
69 El lenguaje ha sido, hasta el desarrollo de la versión 2.0 al menos, un
70 esfuerzo unipersonal de `Walter Bright`_, dados sus problemas a la hora de
71 delegar o aceptar contribuciones. Esto motivó a la comunidad de usuarios de D_
72 a crear bibliotecas base alternativas a la estándar (llamada Phobos_) en las
73 cuales se pudiera trabajar sin las trabas impuestas por el autor del lenguaje.
75 En este contexto nacen primero Mango_ y luego Ares_. Mango_ fue creada por
76 Kris Macleod Bell a principios de 2004 como una biblioteca que provee
77 servicios básicos de entrada/salida (o *I/O* de *input/output* en inglés) de
78 alto rendimiento. Siendo estos servicios algo básico lo más natural hubiera
79 sido que se encuentren en la biblioteca estándar de D_ pero por las
80 dificultades para contribuir a ésta, se desarrolla como una biblioteca
81 separada. A mediados de 2004 Sean Kelly crea Ares_ , con las mismas
82 motivaciones pero con la intención de crear una biblioteca base (conocida en
83 inglés como *runtime*) que incluye los servicios básicos que necesita el
84 lenguaje (información de tipos, manejo de excepciones e hilos, creación
85 y manipulación de objetos, recolector de basura, etc.). Al poco tiempo de
86 liberarse Ares_, Mango_ empieza a utilizarla como biblioteca base.
88 Para comienzos de 2006, se empieza a trabajar en la combinación de ambas
89 bibliotecas para lograr una biblioteca estándar alternativa con un alto grado
90 de cohesión. Finalmente a principios de 2007, coincidiendo por casualidad con
91 la aparición de `D 1.0`_, se anuncia el resultado de este combinación bajo el
92 nombre de Tango_, proveyendo una alternativa completa y madura a la biblioteca
93 estándar de D_ Phobos_. A principios de 2008 los principales desarrolladores
94 de Tango_ (Kris Bell, Sean Kelly, Lars Ivar Igesund y Michael Parker) publican
95 el libro llamado `Learn to Tango with D`_ [BKIP08]_.
97 Esto por un lado fue un gran avance porque dio un impulso muy considerable al
98 lenguaje pero por otro un gran retroceso, porque todavía al día de hoy `D
99 1.0`_ tiene dos bibliotecas base, una estándar pero de peor calidad, menos
100 mantenida y usada; y una alternativa de mayor calidad y apertura a la
101 comunidad (pero no estándar). El peor problema es que ambas son
102 **incompatibles**, por lo que un programa hecho con Tango_ no funciona con
103 Phobos_ y viceversa (a menos que el programador haya invertido una cantidad de
104 tiempo considerable en asegurarse de que funcione con ambas).
106 Esto hace que la compatibilidad de programas y bibliotecas esté muy
107 fragmentada entre las dos bibliotecas base. Si bien no parece que vaya a haber
108 solución alguna a este problema para `D 1.0`_, `D 2.0`_ va en camino
109 a solucionar este problema ya que utiliza DRuntime_, un nuevo intento de Sean
110 Kelly por proveer una biblioteca *runtime* bien organizada y mantenida, que es
111 una adaptación de la biblioteca *runtime* de Tango_ a `D 2.0`_. Sin embargo
112 Tango_ no fue adaptada a `D 2.0`_ todavía, y no hay muchas perspectivas de que
113 sea portada en algún momento, por un lado porque en general la comunidad sigue
114 fragmentada entre muchos usuarios de `D 1.0`_ que no están contentos con los
115 cambios introducidos en `D 2.0`_, en su mayoría usuarios de Tango_, y que no
116 planean migrar a esa versión; y por otro porque el desarrollo de Phobos_ 2.0
117 se ha abierto mucho y tiene muchos colaboradores, por lo tanto la mayor parte
118 de la gente que utiliza `D 2.0`_ está contenta con el estado de Phobos_ 2.0.
122 ----------------------------------------------------------------------------
124 D_ es un lenguaje de programación con sintaxis tipo C, multi-paradigma,
125 compilado, con *tipado* fuerte y estático, buenas capacidades tanto de
126 programación de bajo nivel (*system programming*) como de alto nivel; además
127 es compatible de forma binaria con C (se puede enlazar código objeto C con
128 código objeto D). Con estas características, D_ logra llenar un vacío
129 importante que hay entre lo lenguajes de alto bajo nivel y los de alto nivel
130 [BKIP08]_. Si bien tiene herramientas de muy bajo nivel, que por lo tanto son
131 muy propensas a errores, da una infinidad de mecanismos para evitar el uso de
132 estas herramientas a menos que sea realmente necesario. Además pone mucho
133 énfasis en la programación confiable, para lo cual provee muchos mecanismos
134 para detectar errores en los programas de forma temprana.
136 Si puede pensarse en C++ como un "mejor C", podría decirse que D_ es un "mejor
137 C++", ya que el objetivo del lenguaje es muy similar a C++, pero implementa
138 muchas características que jamás pudieron entrar en el estándar de C++ y lo
139 hace de una forma mucho más limpia, ya que no debe lidiar con problemas de
140 compatibilidad hacia atrás, y cuenta con la experiencia del camino recorrido
141 por C++, pudiendo extraer de él los mejores conceptos pero evitando sus
144 Otra gran diferencia con C++ es la facilidad para ser analizado
145 sintácticamente (*parsing*), ya que fue especialmente diseñado para ser
146 sencillo y a diferencia de C y C++ su gramática es independiente del contexto
147 (*context-free grammar*). Esto permite que D pueda ser compilado en pequeños
148 pasos bien separados:
151 2. Análisis sintáctico.
152 3. Análisis semántico.
154 5. Generación de código.
156 Esto favorece la creación de herramientas dada la facilidad de usar solamente
157 la cantidad de análisis necesario para cada una (por ejemplo un editor de
158 textos puede tener hasta análisis sintáctico para proveer resaltado o un
159 entorno de desarrollo puede proveer herramientas para re-factorizar el código
160 haciendo uso del análisis semántico).
162 Una de las características que nunca pudo entrar en el estándar de C++ es la
163 recolección de basura. D_ no comete el mismo error.
166 Características del lenguaje
167 ----------------------------------------------------------------------------
169 A continuación se enumeran las principales características de D_, agrupadas
170 por unidades funcionales o paradigmas que soporta:
176 Programación genérica y meta-programación
177 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
179 La programación genérica se trata de la capacidad de poder desarrollar
180 algoritmos y estructuras independientes de los tipos que manipulan (pero de
181 forma segura o *type-safe*). Esto fue muy popularizado por C++ gracias a su
182 soporte de plantillas (*templates*) y luego otros lenguajes como Java_ y `C#`_
183 lo siguieron. Sin embargo otros lenguajes proveen formas más avanzadas de
184 programación genérica, gracias a sistemas de tipos más complejos (como
187 La meta-programación se refiere en general a la capacidad de un lenguaje para
188 permitir generar código dentro del mismo programa de forma automática. Esto
189 permite evitar duplicación de código y fue también muy popularizado por el
190 soporte de *templates* de C++, aunque muchos otros lenguajes tienen mejor
191 soporte de meta-programación, en especial los lenguajes dinámicos (como
194 D_ provee las siguientes herramientas para realizar programación genérica
197 ``if`` estático (``static if``)
198 puede verse como similar a la directiva del preprocesador de C/C++ ``#if``,
199 pero a diferencia de esto, en D_ el ``static if`` tiene acceso a todos los
200 símbolos del compilador (constantes, tipos, variables, etc).
204 static if ((void*).sizeof == 4)
205 pragma(msg, "32 bits");
207 Más información en http://www.digitalmars.com/d/1.0/version.html#staticif
209 Inferencia de tipos básica implícita y explícita (mediante ``typeof``)
210 si no se especifica un tipo al declarar una variable, se infiere del tipo
211 de su valor de inicialización.
215 static i = 5; // i es int
216 const d = 6.0; // d es double
217 auto s = "hola"; // s es string (que es un alias de char[])
220 http://www.digitalmars.com/d/1.0/declaration.html#AutoDeclaration
222 Mediante el uso de ``typeof`` se puede solicitar el tipo de una expresión
227 typeof(5 + 6.0) d; // d es double
229 Más información en http://www.digitalmars.com/d/1.0/declaration.html#typeof
231 Iteración sobre colecciones (``foreach``)
232 cualquier tipo de colección (arreglos estáticos y dinámicos, arreglos
233 asociativos, clases, estructuras o delegados) puede ser iterada mediante la
234 sentencia ``foreach``.
238 int[] a = [ 1, 2, 3 ];
244 clases y funciones pueden ser generalizadas. Esto permite desarrollar
245 algoritmos genéricos sin importar el tipo de los datos de entrada, siempre
246 y cuando todos los tipos tengan una *interfaz* común. Esto también es
247 conocido como *polimorfismo en tiempo de compilación*, y es la forma más
248 básica de programación genérica.
252 T sumar(T)(T x, T y) { return x + y; }
253 auto i = sumar!(int)(5, 6); // i == 11
254 auto f = sumar!(float)(5, 6); // j == 11.0f
256 Además se pueden definir bloques de declaraciones generalizadas (esto no
257 es posible en C++), permitiendo instanciar dicho bloque con parámetros
258 particulares. Esto sirve como un mecanismo para la reutilización de código,
259 ya que puede incluirse un mismo bloque en distintos lugares (por ejemplo
260 clases). Un bloque generalizado puede verse como una especie de módulo.
264 template bloque(T, U) {
269 bloque!(int, float).x = 5;
270 float f = bloque!(int, float).foo(7);
272 La utilidad más prominente de los bloques generalizados se da al
273 acompañarse de *mixins*.
275 Instanciación implícita de funciones generalizadas
276 el lenguaje es capaz de deducir los parámetros siempre que no hayan
281 auto i = sumar(5, 6); // i == 11
282 auto f = sumar(5.0f, 6.0f); // f == 11.0f
284 Especialización explícita y parcial de *templates*
285 la especialización de *templates* consiste, al igual que en C++, en proveer
286 una implementación especializada para un tipo de dato (o valor) de los
287 parámetros. Especialización parcial se refiere a la capacidad de
288 especializar un parámetro a través de un subtipo. Por ejemplo, se puede
289 especializar un *template* para cualquier tipo de puntero, o para cualquier
290 tipo de arreglo dinámico, sin necesidad de especificar el tipo al que
291 apunta dicho puntero o el tipo almacenado por el arreglo.
293 Ejemplo de especialización::
295 T sumar(T: int)(T x, T y) { return x + y + 1; }
296 auto i = sumar(5, 6); // i == 12
297 auto f = sumar(5.0f, 6.0f) // f == 11.0f
299 Ejemplo de especialización parcial::
301 T sumar(T: T*)(T x, T y) { return *x + *y; }
303 auto i = sumar(&x, &y); // i == 11
304 float v = 5.0f, w = 6.0f;
305 auto f = sumar(&v, &w); // f == 11.0f
307 Tipos, valores (incluyendo *strings*) y *templates* como parámetros
308 esto es otro bloque de construcción importantísimo para la programación
309 genérica en D, ya que combinando *templates* que toman *strings* como
310 parámetro en combinación con *string mixins* pueden hacerse toda clase de
315 template hash(string s, uint so_far=0) {
316 static if (s.length == 0)
319 const hash = hash!(s[1 .. length], so_far * 11 + s[0]);
321 string s = hash!("hola"); // calculado en tiempo de compilación
323 Cantidad de parámetros variables para *templates*
324 Esto permite implementar tuplas u otros algoritmos que inherentemente deben
325 tomar una cantidad variable de parámetros en tiempo de compilación.
329 double sumar(T...)(T t) {
335 double d = sumar(1, 2.0, 3.0f, 4l); // d == 10.0
337 *CTFE* (*compile-time function execution*)
338 si una función cumple ciertas reglas básicas (como por ejemplo no tener
339 efectos colaterales) puede ser ejecutada en tiempo de compilación en vez de
340 tiempo de ejecución. Esto permite hacer algunos cálculos que no cambian de
341 ejecución en ejecución al momento de compilar, mejorando el rendimiento
342 o permitiendo formas avanzadas de meta-programación. Esta característica se
343 vuelve particularmente útil al combinarse con *string mixins*.
347 int factorial(int n) {
351 return n * factorial(n - 1);
353 static int x = factorial(5); // calculado en tiempo de compilación
354 int x = factorial(5); // calculado en tiempo de ejecución
356 Esta característica es vital para evitar la duplicación de código.
358 *Mixins*, incluyendo *string mixins*
359 la palabra *mixin* tiene significados distintos en varios lenguajes de
360 programación. En D_ *mixin* significa tomar una secuencia arbitraria de
361 declaraciones e insertarla en el contexto (*scope*) actual. Esto puede
362 realizarse a nivel global, en clases, estructuras o funciones. Esto sirve
363 como un mecanismo para evitar duplicación de código que puede ser
364 introducida por la falta de herencia múltiple.
369 mixin bloque!(int, float);
373 float f = a.foo(a.x);
376 mixin bloque!(long, double);
380 double d = a.foo(a.x);
382 *String mixin* se refiere a la capacidad de *incrustar* un *string* que
383 contenga un fragmento de código en un programa como si este fragmento
384 hubiera sido escrito en el código fuente directamente por el programador.
385 Esto permite hacer manipulaciones arbitrariamente complejas en combinación
386 con funciones ejecutadas en tiempo de compilación.
390 string generar_sumar(string var_x, string var_y) {
391 return "return " ~ var_x ~ " + " ~ var_y ~ ";";
394 int sumar(int a, int b) {
395 mixin(generar_sumar!("a", b"));
398 Más información en http://www.digitalmars.com/d/1.0/mixin.html
401 las *expresiones ``is``* permiten la compilación condicional basada en las
402 características de un tipo.
407 static if (is(T == class))
413 Esto provee además una forma simple de reflexión en tiempo de compilación.
416 http://www.digitalmars.com/d/1.0/expression.html#IsExpression
422 Programación de bajo nivel (*system programming*)
423 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
425 Por programación de bajo nivel nos referimos a la capacidad de un lenguaje de
426 manipular el hardware directamente, o al menos la memoria. C es probablemente
427 el lenguaje de bajo nivel más popular, seguido por C++.
429 D_ presenta muchas características de bajo nivel:
431 Compila a código de máquina nativo
432 no es interpretado ni necesita una máquina virtual como otros lenguajes de
433 más alto nivel como Java_, `C#`_, Python_, etc.
435 Provee acceso a *assembly*
436 por lo tanto, acceso directo al *hardware* y la posibilidad de utilizar
437 cualquier característica de éste que no esté disponible en el lenguaje.
439 Una ventaja sobre C y C++ es que el lenguaje *assembly* utilizado dentro de
440 D_ está especificado, por lo que se puede mantener la portabilidad entre
441 compiladores incluso cuando se utiliza *assembly* (mientras que no se
442 cambie de arquitectura, por supuesto).
445 al igual que C y C++, D_ provee la flexibilidad del uso de ``goto``.
448 soporta todos los tipos de C y es ABI [#abi]_ compatible con éste. Esto
449 permite enlazar archivos objeto estándar de C y D_ en un mismo programa.
450 Además permite interoperar con C a través de ``extern (C)``.
452 .. [#abi] Interfaz de Aplicación Binaria (del inglés *Application Binary
457 extern (C) printf(const char* format, ...);
458 printf("3 + 5 == %d\n", 3 + 5); // llama al printf de C
460 Manejo de memoria explícito
461 permite asignar estructuras en el *stack* o en el *heap*, haciendo uso de
462 los servicios del sistema operativo o la biblioteca estándar de C.
464 Objetos y arreglos *livianos*
465 por objetos *livianos* se entiende no-polimórficos. Es decir, un
466 agrupamiento de variables análogo al ``struct`` de C, sin tabla virtual ni
467 otro tipo de *overhead*. Los arreglos *livianos* son arreglos estáticos
468 como en C, cuyo tamaño es fijo, también sin ningún tipo de *overhead* como
469 C. Además puede asignarse un arreglo dinámicamente usando ``malloc()``
470 y utilizar el operador ``[]`` para accederlo.
472 Esto también permite interoperar con C, ya que pueden definirse ``structs``
473 y arreglos que pueden ser intercambiados con dicho lenguaje sin problemas.
482 void* malloc(size_t);
483 size_t strlen(const char *);
484 int gettimeofday(timeval *, void *);
486 char* s = cast(char*) malloc(2);
489 size_t l = strlen(s); // l == 1
491 gettimeofday(&tv, null);
494 la :ref:`d_generic` permite realizar muchas optimizaciones ya que se
495 resuelve en tiempo de compilación y por lo tanto aumenta el rendimiento en
498 Número de punto flotante de 80 bits
499 El tipo ``real`` de D_ tiene precisión de 80 bits si la plataforma lo
500 soporta (por ejemplo en i386).
502 Control de alineación de miembros de una estructura
503 Mediante ``align`` se puede especificar la alineación a tener en una
509 struct paquete_de_red {
513 // paquete_de_red.sizeof == 3
519 Programación de alto nivel
520 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
522 Programación de alto nivel se refiere a construcciones más avanzadas que una
523 sentencia para iterar; expresiones con una semántica más ricas que proveen de
524 mayor expresividad al programador o le permiten focalizarse de mejora manera
525 en los algoritmos independizándose del *hardware* o de como funciona una
526 computadora. Es exactamente el opuesto a :ref:`d_low_level`.
528 En general estas características tienen como efecto secundario una mejora de la
529 productividad de los programadores. D_ adopta herramientas de muchos lenguajes
530 de alto nivel, como Java_ y Python_, por ejemplo:
532 Manejo automático de memoria
533 al igual que C/C++ y prácticamente cualquier lenguaje imperativo maneja
534 automáticamente el *stack*, pero a diferencia de la mayoría de los
535 lenguajes de bajo nivel, D_ permite manejar el *heap* de manera automática
536 también a través de un *recolector de basura*.
538 Sistema de paquetes y módulos (similar a Java_ o Python_)
539 un módulo es una unidad que agrupa clases, funciones y cualquier otra
540 construcción de lenguaje. Un paquete es una agrupación de módulos. D_
541 asocia un módulo a un archivo fuente (y un archivo objeto cuando éste es
542 compilado) y un paquete a un directorio. A diferencia de C/C++ no necesita
543 de un preprocesador para incluir declaraciones de otros *módulos* (en C/C++
544 no existe el concepto de módulo, solo de unidades de compilación).
565 f(); // ejecuta b.f()
567 Funciones y delegados
568 las funciones pueden ser sobrecargadas (funciones con el mismo nombre pero
569 distinta cantidad o tipo de parámetros), pueden especificarse argumentos de
570 entrada, salida o entrada/salida, argumentos por omisión o argumentos
571 evaluados de forma perezosa (*lazy*). Además pueden tener una cantidad de
572 argumentos variables pero manteniendo información de tipos (más seguro que
575 Los *delegados* son punteros a función con un contexto asociado. Este
576 contexto puede ser un objeto (en cuyo caso la función es un método) o un
577 *stack frame* (en cuyo caso la función es una función anidada).
579 Además de esto los delegados son ciudadanos de primera clase
580 [#1stclasscity]_, disponiendo de forma literal (delegado anónimo), lo que
581 permite construcciones de alto nivel muy conveniente. Los argumentos
582 evaluados de forma perezosa no son más que un delegado que se ejecuta solo
585 .. [#1stclasscity] Por ciudadano de primera clase se entiende que se trata
586 de un tipo soportado por completo por el lenguaje, disponiendo de
587 expresiones literales anónimas, pudiendo ser almacenados en variables,
588 estructuras de datos, teniendo una identidad intrínseca, más allá de un
589 nombre dado, etc. En realidad los arreglos asociativos no pueden ser
590 expresados como literales anónimos pero sí tienen una sintaxis especial
591 soportada directamente por el lenguaje.
595 bool buscar(T[] arreglo, T item, bool delegate(T x, T y) igual) {
608 bool encontrado = buscar(personas, p,
609 (Persona x, Persona y) {
610 return x.nombre == y.nombre;
614 Arreglos *dinámicos* y arreglos asociativos
615 los arreglos *dinámicos* son arreglos de longitud variable manejados
616 automáticamente por el lenguaje (análogos al ``std::vector`` de C++).
617 Soportan concatenación (a través del operador ``~``), rebanado o *slicing*
618 (a través del operador ``[x..y]``) y chequeo de límites (*bound checking*).
620 Los arreglos asociativos (también conocidos como *hashes* o diccionarios)
621 también son provistos por el lenguaje.
623 Ambos son ciudadanos de primera clase, disponiendo de forma literal.
627 int[] primos = [ 2, 3, 5, 7, 11, 13, 17, 19 ];
628 primos ~= [ 23, 29 ];
629 auto menores_que_10 = primos[0..4]; // [ 2, 3, 5, 7 ]
631 agenda["Pepe"] = 5555_1234;
634 al igual que los delegados y arreglos dinámicos y asociativos, los
635 *strings* son ciudadanos de primera clase, teniendo forma literal y siendo
636 codificados en UTF-8/16/32. Son un caso particular de arreglo dinámico y es
637 posible utilizarlos en sentencias ``switch``/``case``.
650 ``typedef`` y ``alias``
651 el primero define un nuevo tipo basado en otro. A diferencia de C/C++ el
652 tipo original no puede ser implícitamente convertido al tipo nuevo (excepto
653 valores literales), pero la conversión es válida en el otro sentido
654 (similar a los ``enum`` en C++). Por el contrario, ``alias`` es análogo al
655 ``typedef`` de C/C++ y simplemente es una forma de referirse al mismo tipo
656 con un nombre distinto.
665 foo(i); // error, no compila
670 Documentación embebida
671 D_ provee un sistema de documentación embebida, análogo a lo que proveen
672 Java_ o Python_ en menor medida. Hay comentarios especiales del código que
673 pueden ser utilizados para documentarlo de forma tal que luego el
674 compilador pueda extraer esa información para generar un documento.
676 Más información en http://www.digitalmars.com/d/1.0/ddoc.html
679 D_ soporta números complejos como ciudadanos de primera clase. Soporta
680 forma literal de números imaginarios y complejos.
686 cfloat c = re + im; // c == 1.0 + 5.0i
690 Programación orientada a objetos
691 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
693 La orientación a objetos es probablemente el paradigma más utilizado en la
694 actualidad a la hora de diseñar e implementar un programa. D_ provee muchas
695 herramientas para soportar este paradigma de forma confiable. Entre las
696 características más salientes se encuentran:
699 objetos polimórficos como los de cualquier lenguaje con orientación real
700 a objetos. Estos objetos poseen una tabla virtual para despacho dinámico,
701 todos los métodos son virtuales a menos que se indique lo contrario
702 y tienen semántica de referencia [#drefsem]_. Estos objetos tienen un
703 *overhead* comparados a los objetos *livianos* pero aseguran una semántica
704 segura para trabajar con orientación a objetos, evitando problemas con los
705 que se enfrenta C++ (como *slicing* [#dslicing]_) debido a que permite
706 semántica por valor [#dvalsem]_.
708 .. [#drefsem] Semántica de referencia significa que el tipo es tratado como
709 si fuera un puntero. Nunca se hacen copias del objeto, siempre se pasa
711 .. [#dslicing] Este problema se da en C++ cuando se pasa una clase derivada
712 a una función que acepta una clase base por valor como parámetro. Al
713 realizarse una copia de la clase con el constructor de copia de la clase
714 base, se pierden (o *rebanan*) los atributos de la clase derivada, y la
715 información de tipos en tiempo de ejecución (*RTTI*).
716 .. [#dvalsem] Semántica de valor significa que el tipo es tratado como si
717 fuera un valor concreto. En general se pasa por valor y se hacen copias
718 a menos que se utilice explícitamente un puntero.
720 D_ además soporta tipos de retorno covariantes para funciones virtuales.
721 Esto significa que una función sobreescrita por una clase derivada puede
722 retornar un tipo que sea derivado del tipo retornado por la función
723 original sobreescrita.
731 A test() { return null; }
735 B test() { return null; } // sobreescribe y es covariante con Foo.test()
738 Más información en http://www.digitalmars.com/d/1.0/function.html
741 D_ no soporta herencia múltiple pero sí interfaces. Una interfaz es
742 básicamente una tabla virtual, una definición de métodos virtuales que debe
743 proveer una clase. Las interfaces no proveen una implementación de dichos
744 métodos, ni pueden tener atributos. Esto simplifica mucho el lenguaje y no
745 se pierde flexibilidad porque puede conseguirse el mismo efecto de tener
746 herencia múltiple a través de interfaces y *mixins* para proveer una
747 implementación o atributos en común a varias clases que implementan la
750 Sobrecarga de operadores
751 la sobrecarga de operadores permite que un objeto tenga una sintaxis
752 similar a un tipo de dato nativo. Esto es muy importante además para la
753 programación genérica.
756 al igual que C (con respecto a ``struct``) y C++, pueden anidarse clases
757 dentro de clases. D_ sin embargo provee la posibilidad de acceder
758 a atributos de la instancia exterior desde la anidada.
766 return m; // ok, puede acceder a un miembro de Exterior
771 Esto tiene un pequeño *overhead* ya que la clase ``Anidada`` debe guardar
772 un puntero a la clase ``Exterior``. Si no se necesita este comportamiento
773 es posible evitar este *overhead* utilizando ``static``, en cuyo caso solo
774 puede acceder a atributos estáticos de la clase ``Exterior``.
781 static class Anidada {
783 //return m; // error, miembro de Exterior
784 return n; // ok, miembro estático de Exterior
790 Propiedades (*properties*)
791 en D_ se refiere a funciones miembro que pueden ser tratadas
792 sintácticamente como campos de esa clase/estructura.
797 int data() { return _data; } // propiedad de lectura
798 int data(int value) { return _data = value; } // de escritura
802 f.data = 1; // llama a f.data(1)
803 int i = f.data; // llama a f.data()
805 Además tipos nativos, clases, estructuras y expresiones tienen
806 *properties* predefinidos, por ejemplo:
809 tamaño ocupado en memoria (ejemplo: ``int.sizeof`` -> 4).
812 valor de inicialización por omisión (ejemplo: ``float.init`` -> *NaN*
815 .. [#dnan] Del inglés *Not A Number*, es un valor especial que indica que
816 estamos ante un valor inválido.
819 representación textual del símbolo o expresión (ejemplo:
820 ``(1+2).stringof`` -> ``"1 + 2"``).
823 representación textual del tipo *mutilado* [#dmangle]_.
825 .. [#dmangle] *Name mangling* es el nombre dado comunmente a una técnica
826 necesaria para poder sobrecargar nombres de símbolos. Consiste en
827 codificar los nombres de las funciones tomando como entrada el nombre de
828 la función y la cantidad y tipo de parámetros, asegurando que dos
829 funciones con el mismo nombre pero distintos parámetros (sobrecargada)
830 tengan nombres distintos.
833 alineación de una estructura o tipo.
835 Estos son solo los *properties* predefinidos para todos los tipos, pero hay
836 una cantidad considerable de *properties* extra para cada tipo.
838 Más información sobre *properties* de clases en
839 http://www.digitalmars.com/d/1.0/property.html#classproperties y sobre
840 *properties* predefinidos en
841 http://www.digitalmars.com/d/1.0/property.html
847 Programación confiable
848 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
850 Programación confiable se refiere a las capacidades o facilidades que provee
851 el lenguaje para evitar fallas de manera temprana (o la capacidad de evitar
852 que ciertas fallas puedan existir directamente). D_ presta particular atención
853 a esto y provee las siguientes herramientas:
856 D_ soporta excepciones de manera similar a Java_: provee ``try``, ``catch``
857 y ``finally``. Esto permite que los errores difícilmente pasen
858 silenciosamente sin ser detectados.
861 es una condición que debe cumplirse siempre en un programa, como un chequeo
862 de integridad. Esto es muy utilizado en C/C++, donde ``assert()`` es una
863 *macro* que solo se compila cuando la *macro* ``NDEBUG`` no está definida.
864 Esto permite eliminar los chequeos de integridad del programa, que pueden
865 ser costosos, para versiones que se suponen estables.
867 D_ lleva este concepto más allá y hace al ``assert`` parte del lenguaje.
868 Si una verificación no se cumple, lanza una excepción. El ``assert`` no es
869 compilado cuando se utiliza una opción del compilador.
873 File f = open("archivo");
877 el diseño por contrato es un concepto introducido por el lenguaje Eiffel_
878 a mediados/finales de los '80. Se trata de incorporar en el lenguaje las
879 herramientas para poder aplicar verificaciones formales a las interfaces de
882 D_ implementa las siguientes formas de diseño por contrato (todas se
883 ejecutan siempre y cuando no se compile en modo *release*, de manera de no
884 sacrificar rendimiento cuando es necesario):
886 Pre y post condiciones
889 double raiz_cuadrada(double x)
890 in { // pre-condiciones
893 out (resultado) { // post-condiciones
894 assert (resultado >= 0.0);
896 assert (resultado < x);
898 assert (resultado > x);
900 assert (resultado == 1);
906 Invariantes de representación
907 La invariante de representación es un método de una clase o estructura
908 que es verificada cuando se completa su construcción, antes de la
909 destrucción, antes y después de ejecutar cualquier función miembro
910 pública y cuando se lo requiere de forma explícita utilizando
919 assert(1 <= dia && dia <= 31);
920 assert(0 <= hora && hora < 24);
924 Más información en http://www.digitalmars.com/d/1.0/dbc.html
927 es posible incluir pequeñas pruebas unitarias en el lenguaje. Éstas son
928 ejecutadas (cuando no se compila en modo *release*) al comenzar el
929 programa, antes de que la función ``main()``.
936 assert (fecha.dia == 5);
940 Orden de construcción estática
941 a diferencia de C++, D_ garantiza el orden de inicialización de los
942 módulos. Si bien en C++ no hay módulos si no unidades de compilación, es
943 posible que se ejecute código antes del ``main()`` en C++, si hay, por
944 ejemplo, instancias globales con un constructor definido. C++ no garantiza
945 un orden de inicialización, lo que trae muchos problemas. En D_ se define
946 el orden de inicialización y es el mismo orden en que el usuario importa
949 Inicialización garantizada
950 todas las variables son inicializadas por el lenguaje (a menos que el
951 usuario pida explícitamente que no lo sean). Siempre que sea posible se
952 elijen valores de inicialización que permitan saber al programador que la
953 variable no fue inicializada explícitamente, de manera de poder detectar
954 errores de manera temprana.
958 double d; // inicializado a NaN
959 int x; // inicializado a 0
960 Fecha f; // inicializado a null
961 byte[5] a; // inicializados todos los valores a 0
962 long l = void; // NO inicializado (explícitamente)
964 *RAII* (*Resource Adquisition Is Initialization*)
965 es una técnica muy utilizada en C++ que consiste en reservar recursos por
966 medio de la construcción de un objeto y liberarlos cuando se libera éste.
967 Al llamarse al destructor de manera automática cuando se sale del *scope*,
968 se asegura que el recurso será liberado también.
970 Esta técnica es la base para desarrollar código seguro en cuanto
971 a excepciones (*exception-safe*) [SUTT99]_.
973 En D_ no es tan común utilizar *RAII* dada la existencia del recolector de
974 basura (en la mayoría de los casos el recurso a administrar es
975 sencillamente memoria). Sin embargo en los casos en donde es necesario,
976 puede utilizarse *RAII* mediante la utilización de la palabra reservada
977 ``scope``, que limita la vida de un objeto un bloque de código.
982 this() { /* adquiere recurso */ }
983 ~this() { /* libera recurso */ }
986 scope Archivo archivo = new Archivo;
988 } // en este punto se llama al destructor de archivo
990 Guardias de bloque (*scope guards*)
991 además de poder limitar la vida de una instancia a un *scope*, es posible
992 especificar un bloque de código arbitrario a ejecutar al abandonar un
993 *scope*, ya sea cuando se sale del *scope* normalmente o por una falla.
1000 lock.unlock(); // ejecutado siempre que salga de f()
1001 auto trans = new Transaccion;
1003 trans.commit(); // ejecutado si sale con "return"
1005 trans.rollback(); // ejecutado si sale por una excepción
1007 throw Exception("error"); // lock.unlock() y trans.rollback()
1008 else if (otra_condicion)
1009 return 5; // lock.unlock() y trans.commit()
1010 return 0; // lock.unlock() y trans.commit()
1013 Esta es una nueva forma de poder escribir código *exception-safe*, aunque
1014 el programador debe tener un poco más de cuidado de especificar las
1015 acciones a ejecutar al finalizar el *scope*.
1017 Primitivas de sincronización de hilos
1018 la programación multi-hilo está directamente soportada por el lenguaje,
1019 y se provee una primitiva de sincronización al igual que Java_. La palabra
1020 reservada ``synchronized`` puede aparecer como modificador de métodos (en
1021 cuyo caso se utiliza un *lock* por clase para sincronizar) o como una
1022 sentencia, en cuyo caso se crea un *lock* global por cada bloque
1023 ``synchronized`` a menos que se especifique sobre qué objeto realizar la
1024 sincronización. Por ejemplo::
1027 synchronized void bar() { /* cuerpo */ }
1034 synchronized (this) { /* cuerpo */ }
1040 ----------------------------------------------------------------------------
1042 Hay, hasta el momento, 3 compiladores de D_ de buena calidad: DMD_, GDC_
1045 DMD_ es el compilador de referencia, escrito por `Walter Bright`_. El
1046 *front-end* [#frontend]_ de este compilador ha sido liberado bajo licencia
1047 Artistic_/GPL_ y es utilizado por los otros dos compiladores, por lo tanto en
1048 realidad hay solo un compilador disponible con 3 *back-ends* [#backend]_
1051 .. [#frontend] *Front-end* es la parte del compilador encargada de hacer el
1052 análisis léxico, sintáctico y semántico del código fuente, generando una
1053 representación intermedia que luego el *back-end* convierte a código de
1056 .. [#backend] El *back-end* es la parte del compilador encargada de convertir
1057 la representación intermedia generada por el *front-end* a código de
1060 Con `DMD 1.041`__ se publicó el código fuente completo del compilador, pero
1061 con una licencia muy restrictiva para uso personal, por lo que el único efecto
1062 logrado por esto es que la gente pueda mandar parches o correcciones del
1063 compilador pero no lo convierte en `Software Libre`_, siendo el único de los
1064 3 compiladores que no tiene esta característica.
1066 __ http://www.digitalmars.com/d/1.0/changelog.html#new1_041
1068 El compilador GDC_ es el *front-end* de DMD_ utilizando al compilador GCC_
1069 como *back-end*. Fue un muy buen compilador pero estuvo abandonado por casi
1070 tres años. A mediados de este año recibió un nuevo impulso y de a poco se está
1071 poniendo al día con los *front-ends* actuales de DMD_ 1.0 y 2.0, aunque la
1072 versión 2.0 viene bastante más rezagada y todavía no es una alternativa viable
1075 LDC_ sufrió una suerte similar, es un compilador joven que utiliza como
1076 *back-end* a LLVM_ (una infraestructura modera para construir compiladores),
1077 nacido a mediados de 2007 como un proyecto personal y privado de Tomas
1078 Lindquist Olsen, que estuvo trabajando de forma privada en el proyecto hasta
1079 mediados de 2008, momento en que decide publicar el código mediante una
1080 licencia libre. Para ese entonces el compilador era todavía inestable
1081 y faltaban implementar varias cosas, pero el estado era lo suficientemente
1082 bueno como para captar varios colaboradores muy capaces, como `Christian
1083 Kamm`_ y Frits Van Bommel que rápidamente se convirtieron en parte fundamental
1084 del proyecto. El primer *release* (0.9) de una versión relativamente completa
1085 y estable fue a principios de 2009 que fue seguido por la versión 0.9.1 que
1086 como puntos más salientes agregó soporte para x86-64 y assembly embebido. El
1087 compilador tuvo un crecimiento excepcional pero estuvo muy inactivo por algún
1088 tiempo y, si bien sigue siendo mantenido, en general los nuevos *front-end* de
1089 DMD_ llevan tiempo de integrar y no está al día con el *back-end* de LLVM_
1090 (por ejemplo desde que se actualizó para utilizar LLVM_ 2.7 que perdió la
1091 capacidad de generar símbolos de depuración).
1093 Además de estos compiladores hay varios otros experimentales, pero ninguno de
1094 ellos de calidad suficiente todavía. Por ejemplo hay un compilador
1095 experimental que emite *CIL* (*Common Intermediate Language*), el *bytecode*
1096 de `.NET`_, llamado DNet_. También hay un *front-end* escrito en D_, llamado
1099 Originalmente, dado que GDC_ estaba siendo mantenido y que LDC_ no existía,
1100 este trabajo iba a ser realizado utilizando GDC_ como compilador, dado que al
1101 ser `Software Libre`_ podía ser modificado de ser necesario. Pero finalmente,
1102 dada la poca confiabilidad que presenta la continuidad del desarrollo de tanto
1103 GDC_ como LDC_, y que el código de DMD_ está disponible en su totalidad
1104 (aunque no sea `Software Libre`_ por completo), se optó por utilizar este
1105 último, dado que es la implementación de referencia que fue más constantemente
1106 mantenida y desarrollada.
1109 .. include:: links.rst
1111 .. vim: set ts=3 sts=3 sw=3 et tw=78 spelllang=es :