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)
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:
36 It seems to me that most of the "new" programming languages fall into one
37 of two categories: Those from academia with radical new paradigms and those
38 from large corporations with a focus on RAD and the web. Maybe it's time
39 for a new language born out of practical experience implementing compilers.
41 Esto podría traducirse como:
43 Parece que la mayoría de los lenguajes de programación "nuevos" caen en
44 2 categorías: aquellos académicos con nuevos paradigmas radicales
45 y aquellos de grandes corporaciones con el foco en el desarrollo rápido
46 y web. Tal vez es hora de que nazca un nuevo lenguaje de la experiencia
47 práctica implementando compiladores.
49 La versión 1.0 fue más bien una etiqueta arbitraria que un indicador real de
50 estabilidad y completitud. Luego de liberarse se siguieron agregando nuevas
51 características al lenguaje hasta que se empezó el desarrollo en paralelo de
52 la versión 2.0 al introducirse el concepto de inmutabilidad y funciones
53 *puras* [#dpure]_ (a mediados de 2007).
55 .. [#dpure] Por funciones *puras* en D_ se entiende que no tienen efectos
56 colaterales. Es decir, una función pura siempre que se llame con la misma
57 entrada producirá el mismo resultado. Esto es análogo a como funcionan los
58 lenguajes funcionales en general, abriendo la puerta a la programación de
59 estilo funcional en D_.
61 A partir de este momento la versión 1.0 quedó *teóricamente* congelada,
62 introduciendo solo cambios que arreglen errores (*bug fixes*), agregando
63 nuevas características solamente en la versión 2.0 del lenguaje. La realidad
64 es que se hicieron cambios incompatibles a la versión 1.0 del lenguaje en
65 reiteradas ocasiones, pero se fue tendiendo a cada vez introducir menos
66 cambios incompatibles. Sin embargo al día de hoy el compilador de referencia
67 sigue teniendo algunas características presentes en la especificación del
68 lenguaje sin implementar, por lo que todavía no hay una implementación
69 completa de la versión 1.0 del lenguaje.
71 El lenguaje ha sido, hasta el desarrollo de la versión 2.0 al menos, un
72 esfuerzo unipersonal de `Walter Bright`_, dados sus problemas a la hora de
73 delegar o aceptar contribuciones. Esto motivó a la comunidad de usuarios de D_
74 a crear bibliotecas base alternativas a la estándar (llamada Phobos_) en las
75 cuales se pudiera trabajar sin las trabas impuestas por el autor del lenguaje.
77 En este contexto nacen primero Mango_ y luego Ares_. Mango_ fue creada por
78 Kris Macleod Bell a principios de 2004 como una biblioteca que provee
79 servicios básicos de entrada/salida (o *I/O* de *input/output* en inglés) de
80 alto rendimiento. Siendo estos servicios algo básico lo más natural hubiera
81 sido que se encuentren en la biblioteca estándar de D_ pero por las
82 dificultades para contribuir a ésta, se desarrolla como una biblioteca
83 separada. A mediados de 2004 Sean Kelly crea Ares_ , con las mismas
84 motivaciones pero con la intención de crear una biblioteca base (conocida en
85 inglés como *runtime*) que incluye los servicios básicos que necesita el
86 lenguaje (información de tipos, manejo de excepciones e hilos, creación
87 y manipulación de objetos, recolector de basura, etc.). Al poco tiempo de
88 liberarse Ares_, Mango_ empieza a utilizarla como biblioteca base.
90 Para comienzos de 2006, se empieza a trabajar en la combinación de ambas
91 bibliotecas para lograr una biblioteca estándar alternativa con un alto grado
92 de cohesión. Finalmente a principios de 2007, coincidiendo por casualidad con
93 la aparición de `D 1.0`_, se anuncia el resultado de este combinación bajo el
94 nombre de Tango_, proveyendo una alternativa completa y madura a la biblioteca
95 estándar de D_ Phobos_. A principios de 2008 los principales desarrolladores
96 de Tango_ (Kris Bell, Sean Kelly, Lars Ivar Igesund y Michael Parker) publican
97 el libro llamado `Learn to Tango with D`_ [BKIP08]_.
99 Esto por un lado fue un gran avance porque dio un impulso muy considerable al
100 lenguaje pero por otro un gran retroceso, porque todavía al día de hoy `D
101 1.0`_ tiene dos bibliotecas base, una estándar pero de peor calidad, menos
102 mantenida y usada; y una alternativa de mayor calidad y apertura a la
103 comunidad (pero no estándar). El peor problema es que ambas son
104 **incompatibles**, por lo que un programa hecho con Tango_ no funciona con
105 Phobos_ y viceversa (a menos que el programador haya invertido una cantidad de
106 tiempo considerable en asegurarse que funcione con ambas).
108 Esto hace que la compatibilidad de programas y bibliotecas esté muy
109 fragmentada entre las dos bibliotecas base. Si bien no parece que vaya a haber
110 solución alguna a este problema para `D 1.0`_, `D 2.0`_ va en camino
111 a solucionar este problema ya que utiliza DRuntime_, un nuevo intento de Sean
112 Kelly por proveer una biblioteca *runtime* bien organizada y mantenida, que es
113 una adaptación de la biblioteca *runtime* de Tango_ a `D 2.0`_. Sin embargo
114 Tango_ no fue adaptada a `D 2.0`_ todavía, y no hay muchas perspectivas de que
115 sea portada en algún momento, por un lado porque en general la comunidad sigue
116 fragmentada entre muchos usuarios de `D 1.0`_ que no están contentos con los
117 cambios introducidos en `D 2.0`_, en su mayoría usuarios de Tango_, y que no
118 planean migrar a esa versión; y por otro porque el desarrollo de Phobos_ 2.0
119 se ha abierto mucho y tiene muchos colaboradores, por lo tanto la mayor parte
120 de la gente que utiliza `D 2.0`_ está contenta con el estado de Phobos_ 2.0.
124 ----------------------------------------------------------------------------
126 D_ es un lenguaje de programación con sintaxis tipo C, multi-paradigma,
127 compilado, con *tipado* fuerte y estático, buenas capacidades tanto de
128 programación de bajo nivel (*system programming*) como de alto nivel; además
129 es compatible de forma binaria con C (se puede enlazar código objeto C con
130 código objeto D). Con estas características, D_ logra llenar un vacío
131 importante que hay entre lo lenguajes de alto bajo nivel y los de alto nivel
132 [BKIP08]_. Si bien tiene herramientas de muy bajo nivel, que por lo tanto son
133 muy propensas a errores, da una infinidad de mecanismos para evitar el uso de
134 estas herramientas a menos que sea realmente necesario. Además pone mucho
135 énfasis en la programación confiable, para lo cual provee muchos mecanismos
136 para detectar errores en los programas de forma temprana.
138 Si puede pensarse en C++ como un "mejor C", podría decirse que D_ es un "mejor
139 C++", ya que el objetivo del lenguaje es muy similar a C++, pero implementa
140 muchas características que jamás pudieron entrar en el estándar de C++ y lo
141 hace de una forma mucho más limpia, ya que no debe lidiar con problemas de
142 compatibilidad hacia atrás, y cuenta con la experiencia del camino recorrido
143 por C++, pudiendo extraer de él los mejores conceptos pero evitando sus
146 Una gran diferencia con C++ es que el análisis sintáctico (*parsing*) se puede
147 realizar sin ningún tipo de análisis semántico, dado que a diferencia de éstos
148 su gramática es libre de contexto (*context-free grammar*). Esto acelera
149 y simplifica considerablemente el proceso de compilación.
151 Otra gran diferencia es que D_ decide incluir recolección de basura como parte
152 del lenguaje, mientras que en el comité de estandarización de C++ nunca se
153 llegó a un consenso para su incorporación.
156 Características del lenguaje
157 ----------------------------------------------------------------------------
159 A continuación se enumeran las principales características de D_, agrupadas
160 por unidades funcionales o paradigmas que soporta:
166 Programación genérica y meta-programación
167 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
169 La programación genérica se trata de la capacidad de poder desarrollar
170 algoritmos y estructuras independientes de los tipos que manipulan (pero de
171 forma segura o *type-safe*). Esto fue muy popularizado por C++ gracias a su
172 soporte de plantillas (*templates*) y luego otros lenguajes como Java_ y `C#`_
173 lo siguieron. Sin embargo otros lenguajes proveen formas más avanzadas de
174 programación genérica, gracias a sistemas de tipos más complejos (como
177 La meta-programación se refiere en general a la capacidad de un lenguaje para
178 permitir generar código dentro del mismo programa de forma automática. Esto
179 permite evitar duplicación de código y fue también muy popularizado por el
180 soporte de *templates* de C++, aunque muchos otros lenguajes tienen mejor
181 soporte de meta-programación, en especial los lenguajes dinámicos (como
184 D_ provee las siguientes herramientas para realizar programación genérica
187 ``if`` estático (``static if``)
188 Esta construcción es similar a la directiva del preprocesador de C/C++
189 ``#if``, pero a diferencia de éste, el ``static if`` de D_ tiene acceso
190 a todos los símbolos del compilador (constantes, tipos, variables, etc).
194 static if ((void*).sizeof == 4)
195 pragma(msg, "32 bits");
197 Más información en http://www.digitalmars.com/d/1.0/version.html#staticif
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.
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[])
210 http://www.digitalmars.com/d/1.0/declaration.html#AutoDeclaration
212 Mediante el uso de ``typeof`` se puede solicitar el tipo de una expresión
217 typeof(5 + 6.0) d; // d es double
219 Más información en http://www.digitalmars.com/d/1.0/declaration.html#typeof
221 Iteración sobre colecciones (``foreach``)
222 Cualquier tipo de colección (arreglos estáticos y dinámicos, arreglos
223 asociativos, clases, estructuras o delegados) puede ser iterada mediante la
224 sentencia ``foreach``.
228 int[] a = [ 1, 2, 3 ];
234 Tanto clases como funciones pueden ser generalizadas. Esto permite desarrollar
235 algoritmos genéricos sin importar el tipo de los datos de entrada, siempre
236 y cuando todos los tipos tengan una *interfaz* común. Esto también es
237 conocido como *polimorfismo en tiempo de compilación*, y es la forma más
238 básica de programación genérica.
242 T sumar(T)(T x, T y) { return x + y; }
243 auto i = sumar!(int)(5, 6); // i == 11
244 auto f = sumar!(float)(5, 6); // j == 11.0f
246 Además se pueden definir bloques de declaraciones generalizadas (esto no
247 es posible en C++), permitiendo instanciar dicho bloque con parámetros
248 particulares. Esto sirve como un mecanismo para la reutilización de código,
249 ya que puede incluirse un mismo bloque en distintos lugares (por ejemplo
250 clases). Un bloque generalizado puede verse como una especie de módulo.
254 template bloque(T, U) {
259 bloque!(int, float).x = 5;
260 float f = bloque!(int, float).foo(7);
262 La utilidad más prominente de los bloques generalizados se da al
263 acompañarse de *mixins*.
265 Además las *templates* de D_ tienen las siguientes características
268 Instanciación implícita de funciones generalizadas
269 El lenguaje es capaz de deducir los parámetros siempre que no hayan
274 auto i = sumar(5, 6); // i == 11
275 auto f = sumar(5.0f, 6.0f); // f == 11.0f
277 Especialización explícita y parcial de *templates*
278 La especialización de *templates* consiste, al igual que en C++, en
279 proveer una implementación especializada para un tipo de dato (o valor)
280 de los parámetros. Especialización parcial se refiere a la capacidad
281 de especializar un parámetro a través de un subtipo. Por ejemplo, se
282 puede especializar un *template* para cualquier tipo de puntero, o para
283 cualquier tipo de arreglo dinámico, sin necesidad de especificar el tipo
284 al que apunta dicho puntero o el tipo almacenado por el arreglo.
286 Ejemplo de especialización::
288 T sumar(T: int)(T x, T y) { return x + y + 1; }
289 auto i = sumar(5, 6); // i == 12
290 auto f = sumar(5.0f, 6.0f) // f == 11.0f
292 Ejemplo de especialización parcial::
294 T sumar(T: T*)(T x, T y) { return *x + *y; }
296 auto i = sumar(&x, &y); // i == 11
297 float v = 5.0f, w = 6.0f;
298 auto f = sumar(&v, &w); // f == 11.0f
300 Tipos, valores (incluyendo *strings*) y *templates* como parámetros
301 Este es otro bloque de construcción importantísimo para la programación
302 genérica en D, ya que combinando *templates* que toman *strings* como
303 parámetro en combinación con *string mixins* pueden hacerse toda clase
308 template hash(string s, uint so_far=0) {
309 static if (s.length == 0)
312 const hash = hash!(s[1 .. length], so_far * 11 + s[0]);
314 string s = hash!("hola"); // calculado en tiempo de compilación
316 Cantidad de parámetros variables para *templates*
317 Esta característica permite implementar tuplas y otros algoritmos que
318 inherentemente deben tomar una cantidad variable de parámetros en tiempo
323 double sumar(T...)(T t) {
329 double d = sumar(1, 2.0, 3.0f, 4l); // d == 10.0
331 *CTFE* (*compile-time function execution*)
332 Si una función cumple ciertas reglas básicas (como por ejemplo no tener
333 efectos colaterales) puede ser ejecutada en tiempo de compilación en vez de
334 tiempo de ejecución. Esto permite hacer algunos cálculos que no cambian de
335 ejecución en ejecución al momento de compilar, mejorando el rendimiento
336 o permitiendo formas avanzadas de meta-programación. Esta característica se
337 vuelve particularmente útil al combinarse con *string mixins*.
341 int factorial(int n) {
345 return n * factorial(n - 1);
347 static int x = factorial(5); // calculado en tiempo de compilación
348 int x = factorial(5); // calculado en tiempo de ejecución
350 Esta característica es muy importante para evitar la duplicación de código.
352 *Mixins*, incluyendo *string mixins*
353 La palabra *mixin* tiene significados distintos en varios lenguajes de
354 programación. En D_ *mixin* significa tomar una secuencia arbitraria de
355 declaraciones e insertarla en el contexto (*scope*) actual. Esto puede
356 realizarse a nivel global, en clases, estructuras o funciones. Esto sirve
357 como un mecanismo para evitar duplicación de código que puede ser
358 introducida por la falta de herencia múltiple.
363 mixin bloque!(int, float);
367 float f = a.foo(a.x);
370 mixin bloque!(long, double);
374 double d = a.foo(a.x);
376 *String mixin* se refiere a la capacidad de *incrustar* un *string* que
377 contenga un fragmento de código en un programa como si este fragmento
378 hubiera sido escrito en el código fuente directamente por el programador.
379 Esto permite hacer manipulaciones arbitrariamente complejas en combinación
380 con funciones ejecutadas en tiempo de compilación.
384 string generar_sumar(string var_x, string var_y) {
385 return "return " ~ var_x ~ " + " ~ var_y ~ ";";
388 int sumar(int a, int b) {
389 mixin(generar_sumar!("a", b"));
392 Más información en http://www.digitalmars.com/d/1.0/mixin.html
395 Las *expresiones ``is``* permiten la compilación condicional basada en las
396 características de un tipo.
401 static if (is(T == class))
407 Esto provee además una forma simple de reflexión en tiempo de compilación.
410 http://www.digitalmars.com/d/1.0/expression.html#IsExpression
416 Programación de bajo nivel (*system programming*)
417 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
419 Por programación de bajo nivel nos referimos a la capacidad de un lenguaje de
420 manipular el hardware directamente, o al menos la memoria. C es probablemente
421 el lenguaje de bajo nivel más popular, seguido por C++.
423 D_ presenta muchas características de bajo nivel:
425 Compila a código de máquina nativo
426 Los programas generados por D_ no son interpretados ni necesitan una
427 máquina virtual como otros lenguajes de más alto nivel como Java_, `C#`_,
431 Provee acceso directo al *hardware* y la posibilidad de utilizar cualquier
432 característica de éste que no esté disponible en el lenguaje.
434 Una ventaja sobre C y C++ es que el lenguaje *assembly* utilizado dentro de
435 D_ está especificado, por lo que se puede mantener la portabilidad entre
436 compiladores incluso cuando se utiliza *assembly* (mientras que no se
437 cambie de arquitectura, por supuesto).
440 Al igual que C y C++, D_ provee la flexibilidad del uso de ``goto``.
443 Soporta todos los tipos de C y es ABI [#abi]_ compatible con éste. Esto
444 permite enlazar archivos objeto estándar de C y D_ en un mismo programa.
445 Además permite interoperar con C a través de ``extern (C)``.
447 .. [#abi] Interfaz de Aplicación Binaria (del inglés *Application Binary
452 extern (C) printf(const char* format, ...);
453 printf("3 + 5 == %d\n", 3 + 5); // llama al printf de C
455 Manejo de memoria explícito
456 Permite asignar estructuras en el *stack* o en el *heap*, haciendo uso de
457 los servicios del sistema operativo o la biblioteca estándar de C.
459 Objetos y arreglos *livianos*
460 Por objetos *livianos* se entiende no-polimórficos. Es decir, un
461 agrupamiento de variables análogo al ``struct`` de C, sin tabla virtual ni
462 otro tipo de *overhead*. Los arreglos *livianos* son arreglos estáticos
463 como en C, cuyo tamaño es fijo, también sin ningún tipo de *overhead* como
464 C. Además puede asignarse un arreglo dinámicamente usando ``malloc()``
465 y utilizar el operador ``[]`` para accederlo.
467 Esto también permite interoperar con C, ya que pueden definirse ``structs``
468 y arreglos que pueden ser intercambiados con dicho lenguaje sin problemas.
477 void* malloc(size_t);
478 size_t strlen(const char *);
479 int gettimeofday(timeval *, void *);
481 char* s = cast(char*) malloc(2);
484 size_t l = strlen(s); // l == 1
486 gettimeofday(&tv, null);
489 La :ref:`d_generic` permite realizar muchas optimizaciones ya que se
490 resuelve en tiempo de compilación y por lo tanto aumenta el rendimiento en
493 Número de punto flotante de 80 bits
494 El tipo ``real`` de D_ tiene precisión de 80 bits si la plataforma lo
495 soporta (por ejemplo en i386).
497 Control de alineación de miembros de una estructura
498 Mediante ``align`` se puede especificar la alineación a tener en una
504 struct paquete_de_red {
508 // paquete_de_red.sizeof == 3
514 Programación de alto nivel
515 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
517 Programación de alto nivel se refiere a construcciones más avanzadas que una
518 sentencia para iterar; expresiones con una semántica más ricas que proveen de
519 mayor expresividad al programador o le permiten focalizarse de mejora manera
520 en los algoritmos independizándose del *hardware* o de como funciona una
521 computadora. Es exactamente el opuesto a :ref:`d_low_level`.
523 En general estas características tienen como efecto secundario una mejora de la
524 productividad de los programadores. D_ adopta herramientas de muchos lenguajes
525 de alto nivel, como Java_ y Python_, por ejemplo:
527 Manejo automático de memoria
528 Al igual que C/C++ y prácticamente cualquier lenguaje imperativo maneja
529 automáticamente el *stack*, pero a diferencia de la mayoría de los
530 lenguajes de bajo nivel, D_ permite manejar el *heap* de manera automática
531 también a través de un *recolector de basura*.
533 Sistema de paquetes y módulos (similar a Java_ o Python_)
534 Un módulo es una unidad que agrupa clases, funciones y cualquier otra
535 construcción de lenguaje. Un paquete es una agrupación de módulos. D_
536 asocia un módulo a un archivo fuente (y un archivo objeto cuando éste es
537 compilado) y un paquete a un directorio. A diferencia de C/C++ no necesita
538 de un preprocesador para incluir declaraciones de otros *módulos* (en C/C++
539 no existe el concepto de módulo, solo de unidades de compilación).
560 f(); // ejecuta b.f()
562 Funciones y delegados
563 Las funciones pueden ser sobrecargadas (funciones con el mismo nombre pero
564 distinta cantidad o tipo de parámetros), pueden especificarse argumentos de
565 entrada, salida o entrada/salida, argumentos por omisión o argumentos
566 evaluados de forma perezosa (*lazy*). Además pueden tener una cantidad de
567 argumentos variables pero manteniendo información de tipos (más seguro que
570 Los *delegados* son punteros a función con un contexto asociado. Este
571 contexto puede ser un objeto (en cuyo caso la función es un método) o un
572 *stack frame* (en cuyo caso la función es una función anidada).
574 Además de esto los delegados son ciudadanos de primera clase
575 [#1stclasscity]_, disponiendo de forma literal (delegado anónimo), lo que
576 permite construcciones de alto nivel muy conveniente. Los argumentos
577 evaluados de forma perezosa no son más que un delegado que se ejecuta solo
580 .. [#1stclasscity] Por ciudadano de primera clase se entiende que se trata
581 de un tipo soportado por completo por el lenguaje, disponiendo de
582 expresiones literales anónimas, pudiendo ser almacenados en variables,
583 estructuras de datos, teniendo una identidad intrínseca, más allá de un
584 nombre dado, etc. En realidad los arreglos asociativos no pueden ser
585 expresados como literales anónimos pero sí tienen una sintaxis especial
586 soportada directamente por el lenguaje.
590 bool buscar(T[] arreglo, T item, bool delegate(T x, T y) igual) {
603 bool encontrado = buscar(personas, p,
604 (Persona x, Persona y) {
605 return x.nombre == y.nombre;
609 Arreglos *dinámicos* y arreglos asociativos
610 Los arreglos *dinámicos* son arreglos de longitud variable manejados
611 automáticamente por el lenguaje (análogos al ``std::vector`` de C++).
612 Soportan concatenación (a través del operador ``~``), rebanado o *slicing*
613 (a través del operador ``[x..y]``) y chequeo de límites (*bound checking*).
615 Los arreglos asociativos (también conocidos como *hashes* o diccionarios)
616 también son provistos por el lenguaje.
618 Ambos son ciudadanos de primera clase, disponiendo de forma literal.
622 int[] primos = [ 2, 3, 5, 7, 11, 13, 17, 19 ];
623 primos ~= [ 23, 29 ];
624 auto menores_que_10 = primos[0..4]; // [ 2, 3, 5, 7 ]
626 agenda["Pepe"] = 5555_1234;
629 Al igual que los delegados y arreglos dinámicos y asociativos, los
630 *strings* son ciudadanos de primera clase, teniendo forma literal y siendo
631 codificados en UTF-8/16/32. Son un caso particular de arreglo dinámico y es
632 posible utilizarlos en sentencias ``switch``/``case``.
645 ``typedef`` y ``alias``
646 El primero define un nuevo tipo basado en otro. A diferencia de C/C++ el
647 tipo original no puede ser implícitamente convertido al tipo nuevo (excepto
648 valores literales), pero la conversión es válida en el otro sentido
649 (similar a los ``enum`` en C++). Por el contrario, ``alias`` es análogo al
650 ``typedef`` de C/C++ y simplemente es una forma de referirse al mismo tipo
651 con un nombre distinto.
660 foo(i); // error, no compila
665 Documentación embebida
666 D_ provee un sistema de documentación embebida, análogo a lo que proveen
667 Java_ o Python_ en menor medida. Hay comentarios especiales del código que
668 pueden ser utilizados para documentarlo de forma tal que luego el
669 compilador pueda extraer esa información para generar un documento.
671 Más información en http://www.digitalmars.com/d/1.0/ddoc.html
674 D_ soporta números complejos como ciudadanos de primera clase. Soporta
675 forma literal de números imaginarios y complejos.
681 cfloat c = re + im; // c == 1.0 + 5.0i
685 Programación orientada a objetos
686 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
688 La orientación a objetos es probablemente el paradigma más utilizado en la
689 actualidad a la hora de diseñar e implementar un programa. D_ provee muchas
690 herramientas para soportar este paradigma de forma confiable. Entre las
691 características más salientes se encuentran:
694 Objetos polimórficos como los de cualquier lenguaje con orientación real
695 a objetos. Estos objetos poseen una tabla virtual para despacho dinámico,
696 todos los métodos son virtuales a menos que se indique lo contrario
697 y tienen semántica de referencia [#drefsem]_. Estos objetos tienen un
698 *overhead* comparados a los objetos *livianos* pero aseguran una semántica
699 segura para trabajar con orientación a objetos, evitando problemas con los
700 que se enfrenta C++ (como *slicing* [#dslicing]_) debido a que permite
701 semántica por valor [#dvalsem]_.
703 .. [#drefsem] Semántica de referencia significa que el tipo es tratado como
704 si fuera un puntero. Nunca se hacen copias del objeto, siempre se pasa
706 .. [#dslicing] Este problema se da en C++ cuando se pasa una clase derivada
707 a una función que acepta una clase base por valor como parámetro. Al
708 realizarse una copia de la clase con el constructor de copia de la clase
709 base, se pierden (o *rebanan*) los atributos de la clase derivada, y la
710 información de tipos en tiempo de ejecución (*RTTI*).
711 .. [#dvalsem] Semántica de valor significa que el tipo es tratado como si
712 fuera un valor concreto. En general se pasa por valor y se hacen copias
713 a menos que se utilice explícitamente un puntero.
715 D_ además soporta tipos de retorno covariantes para funciones virtuales.
716 Esto significa que una función sobreescrita por una clase derivada puede
717 retornar un tipo que sea derivado del tipo retornado por la función
718 original sobreescrita.
726 A test() { return null; }
730 B test() { return null; } // sobreescribe y es covariante con Foo.test()
733 Más información en http://www.digitalmars.com/d/1.0/function.html
736 D_ no soporta herencia múltiple pero sí interfaces. Una interfaz es
737 básicamente una tabla virtual, una definición de métodos virtuales que debe
738 proveer una clase. Las interfaces no proveen una implementación de dichos
739 métodos, ni pueden tener atributos. Esto simplifica mucho el lenguaje y no
740 se pierde flexibilidad porque puede conseguirse el mismo efecto de tener
741 herencia múltiple a través de interfaces y *mixins* para proveer una
742 implementación o atributos en común a varias clases que implementan la
745 Sobrecarga de operadores
746 La sobrecarga de operadores permite que un objeto tenga una sintaxis
747 similar a un tipo de dato nativo. Esto es muy importante además para la
748 programación genérica.
751 Al igual que C (con respecto a ``struct``) y C++, pueden anidarse clases
752 dentro de clases. D_ sin embargo provee la posibilidad de acceder
753 a atributos de la instancia exterior desde la anidada.
761 return m; // ok, puede acceder a un miembro de Exterior
766 Esto tiene un pequeño *overhead* ya que la clase ``Anidada`` debe guardar
767 un puntero a la clase ``Exterior``. Si no se necesita este comportamiento
768 es posible evitar este *overhead* utilizando ``static``, en cuyo caso solo
769 puede acceder a atributos estáticos de la clase ``Exterior``.
776 static class Anidada {
778 //return m; // error, miembro de Exterior
779 return n; // ok, miembro estático de Exterior
785 Propiedades (*properties*)
786 En D_ se refiere a funciones miembro que pueden ser tratadas
787 sintácticamente como campos de esa clase/estructura.
792 int data() { return _data; } // propiedad de lectura
793 int data(int value) { return _data = value; } // de escritura
797 f.data = 1; // llama a f.data(1)
798 int i = f.data; // llama a f.data()
800 Además tipos nativos, clases, estructuras y expresiones tienen
801 *properties* predefinidos, por ejemplo:
804 Tamaño ocupado en memoria (ejemplo: ``int.sizeof`` -> 4).
807 Valor de inicialización por omisión (ejemplo: ``float.init`` -> *NaN*
810 .. [#dnan] Del inglés *Not A Number*, es un valor especial que indica que
811 estamos ante un valor inválido.
814 Representación textual del símbolo o expresión (ejemplo:
815 ``(1+2).stringof`` -> ``"1 + 2"``).
818 Representación textual del tipo *mutilado* [#dmangle]_.
820 .. [#dmangle] *Name mangling* es el nombre dado comunmente a una técnica
821 necesaria para poder sobrecargar nombres de símbolos. Consiste en
822 codificar los nombres de las funciones tomando como entrada el nombre de
823 la función y la cantidad y tipo de parámetros, asegurando que dos
824 funciones con el mismo nombre pero distintos parámetros (sobrecargada)
825 tengan nombres distintos.
828 Alineación de una estructura o tipo.
830 Estos son solo los *properties* predefinidos para todos los tipos, pero hay
831 una cantidad considerable de *properties* extra para cada tipo.
833 Más información sobre *properties* de clases en
834 http://www.digitalmars.com/d/1.0/property.html#classproperties y sobre
835 *properties* predefinidos en
836 http://www.digitalmars.com/d/1.0/property.html
842 Programación confiable
843 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
845 Programación confiable se refiere a las capacidades o facilidades que provee
846 el lenguaje para evitar fallas de manera temprana (o la capacidad de evitar
847 que ciertas fallas puedan existir directamente). D_ presta particular atención
848 a esto y provee las siguientes herramientas:
851 D_ soporta excepciones de manera similar a Java_: provee ``try``, ``catch``
852 y ``finally``. Esto permite que los errores difícilmente pasen
853 silenciosamente sin ser detectados.
856 Es una condición que debe cumplirse siempre en un programa, como un chequeo
857 de integridad. Esto es muy utilizado en C/C++, donde ``assert()`` es una
858 *macro* que solo se compila cuando la *macro* ``NDEBUG`` no está definida.
859 Esto permite eliminar los chequeos de integridad del programa, que pueden
860 ser costosos, para versiones que se suponen estables.
862 D_ lleva este concepto más allá y hace al ``assert`` parte del lenguaje.
863 Si una verificación no se cumple, lanza una excepción. El ``assert`` no es
864 compilado cuando se utiliza una opción del compilador.
868 File f = open("archivo");
872 El diseño por contrato es un concepto introducido por el lenguaje Eiffel_
873 a mediados/finales de los '80. Se trata de incorporar en el lenguaje las
874 herramientas para poder aplicar verificaciones formales a las interfaces de
877 D_ implementa las siguientes formas de diseño por contrato (todas se
878 ejecutan siempre y cuando no se compile en modo *release*, de manera de no
879 sacrificar rendimiento cuando es necesario):
881 Pre y post condiciones
884 double raiz_cuadrada(double x)
885 in { // pre-condiciones
888 out (resultado) { // post-condiciones
889 assert (resultado >= 0.0);
891 assert (resultado < x);
893 assert (resultado > x);
895 assert (resultado == 1);
901 Invariantes de representación
902 La invariante de representación es un método de una clase o estructura
903 que es verificada cuando se completa su construcción, antes de la
904 destrucción, antes y después de ejecutar cualquier función miembro
905 pública y cuando se lo requiere de forma explícita utilizando
914 assert(1 <= dia && dia <= 31);
915 assert(0 <= hora && hora < 24);
919 Más información en http://www.digitalmars.com/d/1.0/dbc.html
922 Es posible incluir pequeñas pruebas unitarias en el lenguaje. Éstas son
923 ejecutadas (cuando no se compila en modo *release*) al comenzar el
924 programa, antes de que la función ``main()``.
931 assert (fecha.dia == 5);
935 Orden de construcción estática
936 A diferencia de C++, D_ garantiza el orden de inicialización de los
937 módulos. Si bien en C++ no hay módulos si no unidades de compilación, es
938 posible que se ejecute código antes del ``main()`` en C++, si hay, por
939 ejemplo, instancias globales con un constructor definido. C++ no garantiza
940 un orden de inicialización, lo que trae muchos problemas. En D_ se define
941 el orden de inicialización y es el mismo orden en que el usuario importa
944 Inicialización garantizada
945 Todas las variables son inicializadas por el lenguaje (a menos que el
946 usuario pida explícitamente que no lo sean). Siempre que sea posible se
947 elijen valores de inicialización que permitan saber al programador que la
948 variable no fue inicializada explícitamente, de manera de poder detectar
949 errores de manera temprana.
953 double d; // inicializado a NaN
954 int x; // inicializado a 0
955 Fecha f; // inicializado a null
956 byte[5] a; // inicializados todos los valores a 0
957 long l = void; // NO inicializado (explícitamente)
959 *RAII* (*Resource Adquisition Is Initialization*)
960 Es una técnica muy utilizada en C++ que consiste en reservar recursos por
961 medio de la construcción de un objeto y liberarlos cuando se libera éste.
962 Al llamarse al destructor de manera automática cuando se sale del *scope*,
963 se asegura que el recurso será liberado también.
965 Esta técnica es la base para desarrollar código seguro en cuanto
966 a excepciones (*exception-safe*) [SUTT99]_.
968 En D_ no es tan común utilizar *RAII* dada la existencia del recolector de
969 basura (en la mayoría de los casos el recurso a administrar es
970 sencillamente memoria). Sin embargo en los casos en donde es necesario,
971 puede utilizarse *RAII* mediante la utilización de la palabra reservada
972 ``scope``, que limita la vida de un objeto un bloque de código.
977 this() { /* adquiere recurso */ }
978 ~this() { /* libera recurso */ }
981 scope Archivo archivo = new Archivo;
983 } // en este punto se llama al destructor de archivo
985 Guardias de bloque (*scope guards*)
986 Además de poder limitar la vida de una instancia a un *scope*, es posible
987 especificar un bloque de código arbitrario a ejecutar al abandonar un
988 *scope*, ya sea cuando se sale del *scope* normalmente o por una falla.
995 lock.unlock(); // ejecutado siempre que salga de f()
996 auto trans = new Transaccion;
998 trans.commit(); // ejecutado si sale con "return"
1000 trans.rollback(); // ejecutado si sale por una excepción
1002 throw Exception("error"); // lock.unlock() y trans.rollback()
1003 else if (otra_condicion)
1004 return 5; // lock.unlock() y trans.commit()
1005 return 0; // lock.unlock() y trans.commit()
1008 Esta es una nueva forma de poder escribir código *exception-safe*, aunque
1009 el programador debe tener un poco más de cuidado de especificar las
1010 acciones a ejecutar al finalizar el *scope*.
1012 Primitivas de sincronización de hilos
1013 La programación multi-hilo está directamente soportada por el lenguaje,
1014 y se provee una primitiva de sincronización al igual que Java_. La palabra
1015 reservada ``synchronized`` puede aparecer como modificador de métodos (en
1016 cuyo caso se utiliza un *lock* por clase para sincronizar) o como una
1017 sentencia, en cuyo caso se crea un *lock* global por cada bloque
1018 ``synchronized`` a menos que se especifique sobre qué objeto realizar la
1019 sincronización. Por ejemplo::
1022 synchronized void bar() { /* cuerpo */ }
1029 synchronized (this) { /* cuerpo */ }
1035 ----------------------------------------------------------------------------
1037 Hay, hasta el momento, 3 compiladores de D_ de buena calidad: DMD_, GDC_
1040 DMD_ es el compilador de referencia, escrito por `Walter Bright`_. El
1041 *front-end* [#frontend]_ de este compilador ha sido liberado bajo licencia
1042 Artistic_/GPL_ y es utilizado por los otros dos compiladores, por lo tanto en
1043 realidad hay solo un compilador disponible con 3 *back-ends* [#backend]_
1046 .. [#frontend] *Front-end* es la parte del compilador encargada de hacer el
1047 análisis léxico, sintáctico y semántico del código fuente, generando una
1048 representación intermedia que luego el *back-end* convierte a código de
1051 .. [#backend] El *back-end* es la parte del compilador encargada de convertir
1052 la representación intermedia generada por el *front-end* a código de
1055 Con `DMD 1.041`__ se publicó el código fuente completo del compilador, pero
1056 con una licencia muy restrictiva para uso personal, por lo que el único efecto
1057 logrado por esto es que la gente pueda mandar parches o correcciones del
1058 compilador pero no lo convierte en `Software Libre`_, siendo el único de los
1059 3 compiladores que no tiene esta característica.
1061 __ http://www.digitalmars.com/d/1.0/changelog.html#new1_041
1063 El compilador GDC_ es el *front-end* de DMD_ utilizando al compilador GCC_
1064 como *back-end*. Fue un muy buen compilador pero estuvo abandonado por casi
1065 tres años. A mediados de este año recibió un nuevo impulso y de a poco se está
1066 poniendo al día con los *front-ends* actuales de DMD_ 1.0 y 2.0, aunque la
1067 versión 2.0 viene bastante más rezagada y todavía no es una alternativa viable
1070 LDC_ sufrió una suerte similar, es un compilador joven que utiliza como
1071 *back-end* a LLVM_ (una infraestructura modera para construir compiladores),
1072 nacido a mediados de 2007 como un proyecto personal y privado de Tomas
1073 Lindquist Olsen, que estuvo trabajando de forma privada en el proyecto hasta
1074 mediados de 2008, momento en que decide publicar el código mediante una
1075 licencia libre. Para ese entonces el compilador era todavía inestable
1076 y faltaban implementar varias cosas, pero el estado era lo suficientemente
1077 bueno como para captar varios colaboradores muy capaces, como `Christian
1078 Kamm`_ y Frits Van Bommel que rápidamente se convirtieron en parte fundamental
1079 del proyecto. El primer *release* (0.9) de una versión relativamente completa
1080 y estable fue a principios de 2009 que fue seguido por la versión 0.9.1 que
1081 como puntos más salientes agregó soporte para x86-64 y assembly embebido. El
1082 compilador tuvo un crecimiento excepcional pero estuvo muy inactivo por algún
1083 tiempo y, si bien sigue siendo mantenido, en general los nuevos *front-end* de
1084 DMD_ llevan tiempo de integrar y no está al día con el *back-end* de LLVM_
1085 (por ejemplo desde que se actualizó para utilizar LLVM_ 2.7 que perdió la
1086 capacidad de generar símbolos de depuración).
1088 Además de estos compiladores hay varios otros experimentales, pero ninguno de
1089 ellos de calidad suficiente todavía. Por ejemplo hay un compilador
1090 experimental que emite *CIL* (*Common Intermediate Language*), el *bytecode*
1091 de `.NET`_, llamado DNet_. También hay un *front-end* escrito en D_, llamado
1094 Originalmente, dado que GDC_ estaba siendo mantenido y que LDC_ no existía,
1095 este trabajo iba a ser realizado utilizando GDC_ como compilador, dado que al
1096 ser `Software Libre`_ podía ser modificado de ser necesario. Pero finalmente,
1097 dada la poca confiabilidad que presenta la continuidad del desarrollo de tanto
1098 GDC_ como LDC_, y que el código de DMD_ está disponible en su totalidad
1099 (aunque no sea `Software Libre`_ por completo), se optó por utilizar este
1100 último, dado que es la implementación de referencia que fue más constantemente
1101 mantenida y desarrollada.
1104 .. include:: links.rst
1106 .. vim: set ts=3 sts=3 sw=3 et tw=78 spelllang=es :