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, REVISADO
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`__, aún inestable y en la cual
20 se está experimentando principalmente sobre multi-procesamiento.
25 El lenguaje fue diseñado e implementado por `Walter Bright`_, desarrollador
26 principal de Zortech C++, uno de los primeros compiladores de C++ que
27 compilaba a código nativo, y está fuertemente influenciado por éste. Sin
28 embargo toma muchos conceptos de otros lenguajes de más alto nivel, como Java_
29 o incluso lenguajes dinámicos como Perl_, Python_ y Ruby_.
31 El origen del lenguaje está plasmado en su sitio web, en donde se cita:
33 It seems to me that most of the "new" programming languages fall into one
34 of two categories: Those from academia with radical new paradigms and those
35 from large corporations with a focus on RAD and the web. Maybe it's time
36 for a new language born out of practical experience implementing compilers.
38 Esto podría traducirse como:
40 Parece que la mayoría de los lenguajes de programación "nuevos" caen en
41 2 categorías: aquellos académicos con nuevos paradigmas radicales
42 y aquellos de grandes corporaciones con el foco en el desarrollo rápido
43 y web. Tal vez es hora de que nazca un nuevo lenguaje de la experiencia
44 práctica implementando compiladores.
46 La versión 1.0 fue más bien una etiqueta arbitraria que un indicador real de
47 estabilidad y completitud. Luego de liberarse se siguieron agregando nuevas
48 características al lenguaje hasta que se empezó el desarrollo en paralelo de
49 la versión 2.0 al introducirse el concepto de inmutabilidad y funciones
50 *puras* [#dpure]_ (a mediados de 2007).
52 .. [#dpure] Por funciones *puras* en D_ se entiende que no tienen efectos
53 colaterales. Es decir, una función pura siempre que se llame con la misma
54 entrada producirá el mismo resultado. Esto es análogo a como funcionan los
55 lenguajes funcionales en general, abriendo la puerta a la programación de
56 estilo funcional en D_.
58 A partir de este momento la versión 1.0 quedó *teóricamente* congelada,
59 introduciendo solo cambios que arreglen errores (*bug fixes*), agregando
60 nuevas características solamente en la versión 2.0 del lenguaje. La realidad
61 es que se hicieron cambios incompatibles a la versión 1.0 del lenguaje en
62 reiteradas ocasiones, pero se fue tendiendo a cada vez introducir menos
63 cambios incompatibles. Sin embargo al día de hoy el compilador de referencia
64 sigue teniendo algunas características presentes en la especificación del
65 lenguaje sin implementar, por lo que todavía no hay una implementación
66 completa de la versión 1.0 del lenguaje.
68 El lenguaje ha sido, hasta el desarrollo de la versión 2.0 al menos, un
69 esfuerzo unipersonal de `Walter Bright`_, dados sus problemas a la hora de
70 delegar o aceptar contribuciones. Esto motivó a la comunidad de usuarios de D_
71 a crear bibliotecas base alternativas a la estándar (llamada Phobos_) en las
72 cuales se pudiera trabajar sin las trabas impuestas por el autor del lenguaje.
74 En este contexto nacen primero Mango_ y luego Ares_. Mango_ fue creada por
75 Kris Macleod Bell a principios de 2004 como una biblioteca que provee
76 servicios básicos de entrada/salida (o *I/O* de *input/output* en inglés) de
77 alto rendimiento. Siendo estos servicios algo básico lo más natural hubiera
78 sido que se encuentren en la biblioteca estándar de D_ pero por las
79 dificultades para contribuir a ésta, se desarrolla como una biblioteca
80 separada. A mediados de 2004 Sean Kelly crea Ares_ , con las mismas
81 motivaciones pero con la intención de crear una biblioteca base (conocida en
82 inglés como *runtime*) que incluye los servicios básicos que necesita el
83 lenguaje (información de tipos, manejo de excepciones e hilos, creación
84 y manipulación de objetos, recolector de basura, etc.). Al poco tiempo de
85 liberarse Ares_, Mango_ empieza a utilizarla como biblioteca base.
87 Para comienzos de 2006, se empieza a trabajar en la combinación de ambas
88 bibliotecas para lograr una biblioteca estándar alternativa con un alto grado
89 de cohesión. Finalmente a principios de 2007, coincidiendo por casualidad con
90 la aparición de `D 1.0`_, se anuncia el resultado de este combinación bajo el
91 nombre de Tango_, proveyendo una alternativa completa y madura a la biblioteca
92 estándar de D_ Phobos_. A principios de 2008 los principales desarrolladores
93 de Tango_ (Kris Bell, Sean Kelly, Lars Ivar Igesund y Michael Parker) publican
94 el libro llamado `Learn to Tango with D`_ [BKIP08]_.
96 Esto por un lado fue un gran avance porque dio un impulso muy considerable al
97 lenguaje pero por otro un gran retroceso, porque todavía al día de hoy `D
98 1.0`_ tiene dos bibliotecas base, una estándar pero de peor calidad, menos
99 mantenida y usada; y una alternativa de mayor calidad y apertura a la
100 comunidad (pero no estándar). El peor problema es que ambas son
101 **incompatibles**, por lo que un programa hecho con Tango_ no funciona con
102 Phobos_ y viceversa (a menos que el programador haya invertido una cantidad de
103 tiempo considerable en asegurarse de que funcione con ambas).
105 Esto hace que la compatibilidad de programas y bibliotecas esté muy
106 fragmentada entre las dos bibliotecas base. Si bien no parece que vaya a haber
107 solución alguna a este problema para D 1.0, D 2.0 va en camino a solucionar
108 este problema ya que utiliza DRuntime_, un nuevo intento de Sean Kelly por
109 proveer una biblioteca *runtime* bien organizada y mantenida, que es una
110 adaptación de la biblioteca *runtime* de Tango_ a `D 2.0`_. Si bien todavía
111 Tango_ no fue adaptada a `D 2.0`_, se espera que cuando esto pase compartan la
112 misma biblioteca *runtime* permitiendo que bibliotecas y programas hechos para
113 y Phobos_ 2.0 puedan coexistir sin problemas.
117 ----------------------------------------------------------------------------
119 D_ es un lenguaje de programación con sintaxis tipo C, multi-paradigma,
120 compilado, con *tipado* fuerte y estático, buenas capacidades tanto de
121 programación de bajo nivel (*system programming*) como de alto nivel; además
122 es compatible de forma binaria con C (se puede enlazar código objeto C con
123 código objeto D). Con estas características, D_ logra llenar un vacío
124 importante que hay entre lo lenguajes de alto bajo nivel y los de alto nivel
125 [BKIP08]_. Si bien tiene herramientas de muy bajo nivel, que por lo tanto son
126 muy propensas a errores, da una infinidad de mecanismos para evitar el uso de
127 estas herramientas a menos que sea realmente necesario. Además pone mucho
128 énfasis en la programación confiable, para lo cual provee muchos mecanismos
129 para detectar errores en los programas de forma temprana.
131 Si puede pensarse en C++ como un "mejor C", podría decirse que D_ es un "mejor
132 C++", ya que el objetivo del lenguaje es muy similar a C++, pero implementa
133 muchas características que jamás pudieron entrar en el estándar de C++ y lo
134 hace de una forma mucho más limpia, ya que no debe lidiar con problemas de
135 compatibilidad hacia atrás, y cuenta con la experiencia del camino recorrido
136 por C++, pudiendo extraer de él los mejores conceptos pero evitando sus
139 Otra gran diferencia con C++ es la facilidad para ser analizado
140 sintácticamente (*parsing*), ya que fue especialmente diseñado para ser
141 sencillo y a diferencia de C y C++ su gramática es independiente del contexto
142 (*context-free grammar*). Esto permite que D pueda ser compilado en pequeños
143 pasos bien separados:
146 2. Análisis sintáctico.
147 3. Análisis semántico.
149 5. Generación de código.
151 Esto favorece la creación de herramientas dada la facilidad de usar solamente
152 la cantidad de análisis necesario para cada una (por ejemplo un editor de
153 textos puede tener hasta análisis sintáctico para proveer resaltado o un
154 entorno de desarrollo puede proveer herramientas para re-factorizar el código
155 haciendo uso del análisis semántico).
157 Una de las características que nunca pudo entrar en el estándar de C++ es la
158 recolección de basura. D_ no comete el mismo error.
161 Características del lenguaje
162 ----------------------------------------------------------------------------
164 A continuación se enumeran las principales características de D_, agrupadas
165 por unidades funcionales o paradigmas que soporta:
171 Programación genérica y meta-programación
172 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
174 La programación genérica se trata de la capacidad de poder desarrollar
175 algoritmos y estructuras independientes de los tipos que manipulan (pero de
176 forma segura o *type-safe*). Esto fue muy popularizado por C++ gracias a su
177 soporte de plantillas (*templates*) y luego otros lenguajes como Java_ y `C#`_
178 lo siguieron. Sin embargo otros lenguajes proveen formas más avanzadas de
179 programación genérica, gracias a sistemas de tipos más complejos (como
182 La meta-programación se refiere en general a la capacidad de un lenguaje para
183 permitir generar código dentro del mismo programa de forma automática. Esto
184 permite evitar duplicación de código y fue también muy popularizado por el
185 soporte de *templates* de C++, aunque muchos otros lenguajes tienen mejor
186 soporte de meta-programación, en especial los lenguajes dinámicos (como
189 D_ provee las siguientes herramientas para realizar programación genérica
192 ``if`` estático (``static if``)
193 puede verse como similar a la directiva del preprocesador de C/C++ ``#if``,
194 pero a diferencia de esto, en D_ el ``static if`` tiene acceso a todos los
195 símbolos del compilador (constantes, tipos, variables, etc).
199 static if ((void*).sizeof == 4)
200 pragma(msg, "32 bits");
202 Más información en http://www.digitalmars.com/d/1.0/version.html#staticif
204 Inferencia de tipos básica implícita y explícita (mediante ``typeof``)
205 si no se especifica un tipo al declarar una variable, se infiere del tipo
206 de su valor de inicialización.
210 static i = 5; // i es int
211 const d = 6.0; // d es double
212 auto s = "hola"; // s es string (que es un alias de char[])
215 http://www.digitalmars.com/d/1.0/declaration.html#AutoDeclaration
217 Mediante el uso de ``typeof`` se puede solicitar el tipo de una expresión
222 typeof(5 + 6.0) d; // d es double
224 Más información en http://www.digitalmars.com/d/1.0/declaration.html#typeof
226 Iteración sobre colecciones (``foreach``)
227 cualquier tipo de colección (arreglos estáticos y dinámicos, arreglos
228 asociativos, clases, estructuras o delegados) puede ser iterada mediante la
229 sentencia ``foreach``.
233 int[] a = [ 1, 2, 3 ];
239 clases y funciones pueden ser generalizadas. Esto permite desarrollar
240 algoritmos genéricos sin importar el tipo de los datos de entrada, siempre
241 y cuando todos los tipos tengan una *interfaz* común. Esto también es
242 conocido como *polimorfismo en tiempo de compilación*, y es la forma más
243 básica de programación genérica.
247 T sumar(T)(T x, T y) { return x + y; }
248 auto i = sumar!(int)(5, 6); // i == 11
249 auto f = sumar!(float)(5, 6); // j == 11.0f
251 Además se pueden definir bloques de declaraciones generalizadas (esto no
252 es posible en C++), permitiendo instanciar dicho bloque con parámetros
253 particulares. Esto sirve como un mecanismo para la reutilización de código,
254 ya que puede incluirse un mismo bloque en distintos lugares (por ejemplo
255 clases). Un bloque generalizado puede verse como una especie de módulo.
259 template bloque(T, U) {
264 bloque!(int, float).x = 5;
265 float f = bloque!(int, float).foo(7);
267 La utilidad más prominente de los bloques generalizados se da al
268 acompañarse de *mixins*.
270 Instanciación implícita de funciones generalizadas
271 el lenguaje es capaz de deducir los parámetros siempre que no hayan
276 auto i = sumar(5, 6); // i == 11
277 auto f = sumar(5.0f, 6.0f); // f == 11.0f
279 Especialización explícita y parcial de *templates*
280 la especialización de *templates* consiste, al igual que en C++, en proveer
281 una implementación especializada para un tipo de dato (o valor) de los
282 parámetros. Especialización parcial se refiere a la capacidad de
283 especializar un parámetro a través de un subtipo. Por ejemplo, se puede
284 especializar un *template* para cualquier tipo de puntero, o para cualquier
285 tipo de arreglo dinámico, sin necesidad de especificar el tipo al que
286 apunta dicho puntero o el tipo almacenado por el arreglo.
288 Ejemplo de especialización::
290 T sumar(T: int)(T x, T y) { return x + y + 1; }
291 auto i = sumar(5, 6); // i == 12
292 auto f = sumar(5.0f, 6.0f) // f == 11.0f
294 Ejemplo de especialización parcial::
296 T sumar(T: T*)(T x, T y) { return *x + *y; }
298 auto i = sumar(&x, &y); // i == 11
299 float v = 5.0f, w = 6.0f;
300 auto f = sumar(&v, &w); // f == 11.0f
302 Tipos, valores (incluyendo *strings*) y *templates* como parámetros
303 esto es otro bloque de construcción importantísimo para la programación
304 genérica en D, ya que combinando *templates* que toman *strings* como
305 parámetro en combinación con *string mixins* pueden hacerse toda clase de
310 template hash(string s, uint so_far=0) {
311 static if (s.length == 0)
314 const hash = hash!(s[1 .. length], so_far * 11 + s[0]);
316 string s = hash!("hola"); // calculado en tiempo de compilación
318 Cantidad de parámetros variables para *templates*
319 Esto permite implementar tuplas u otros algoritmos que inherentemente deben
320 tomar una cantidad variable de parámetros en tiempo de compilación.
324 double sumar(T...)(T t) {
330 double d = sumar(1, 2.0, 3.0f, 4l); // d == 10.0
332 *CTFE* (*compile-time function execution*)
333 si una función cumple ciertas reglas básicas (como por ejemplo no tener
334 efectos colaterales) puede ser ejecutada en tiempo de compilación en vez de
335 tiempo de ejecución. Esto permite hacer algunos cálculos que no cambian de
336 ejecución en ejecución al momento de compilar, mejorando el rendimiento
337 o permitiendo formas avanzadas de meta-programación. Esta característica se
338 vuelve particularmente útil al combinarse con *string mixins*.
342 int factorial(int n) {
346 return n * factorial(n - 1);
348 static int x = factorial(5); // calculado en tiempo de compilación
349 int x = factorial(5); // calculado en tiempo de ejecución
351 Esta característica es vital para evitar la duplicación de código.
353 *Mixins*, incluyendo *string mixins*
354 la palabra *mixin* tiene significados distintos en varios lenguajes de
355 programación. En D_ *mixin* significa tomar una secuencia arbitraria de
356 declaraciones e insertarla en el contexto (*scope*) actual. Esto puede
357 realizarse a nivel global, en clases, estructuras o funciones. Esto sirve
358 como un mecanismo para evitar duplicación de código que puede ser
359 introducida por la falta de herencia múltiple.
364 mixin bloque!(int, float);
368 float f = a.foo(a.x);
371 mixin bloque!(long, double);
375 double d = a.foo(a.x);
377 *String mixin* se refiere a la capacidad de *incrustar* un *string* que
378 contenga un fragmento de código en un programa como si este fragmento
379 hubiera sido escrito en el código fuente directamente por el programador.
380 Esto permite hacer manipulaciones arbitrariamente complejas en combinación
381 con funciones ejecutadas en tiempo de compilación.
385 string generar_sumar(string var_x, string var_y) {
386 return "return " ~ var_x ~ " + " ~ var_y ~ ";";
389 int sumar(int a, int b) {
390 mixin(generar_sumar!("a", b"));
393 Más información en http://www.digitalmars.com/d/1.0/mixin.html
396 las *expresiones ``is``* permiten la compilación condicional basada en las
397 características de un tipo.
402 static if (is(T == class))
408 Esto provee además una forma simple de reflexión en tiempo de compilación.
411 http://www.digitalmars.com/d/1.0/expression.html#IsExpression
417 Programación de bajo nivel (*system programming*)
418 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
420 Por programación de bajo nivel nos referimos a la capacidad de un lenguaje de
421 manipular el hardware directamente, o al menos la memoria. C es probablemente
422 el lenguaje de bajo nivel más popular, seguido por C++.
424 D_ presenta muchas características de bajo nivel:
426 Compila a código de máquina nativo
427 no es interpretado ni necesita una máquina virtual como otros lenguajes de
428 más alto nivel como Java_, `C#`_, Python_, etc.
430 Provee acceso a *assembly*
431 por lo tanto, acceso directo al *hardware* y la posibilidad de utilizar
432 cualquier 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 en la actualidad está
1065 abandonado. No hay un *release* desde agosto de 2007 y no hay actualizaciones
1066 serias del código desde mediados de 2008, por lo que no parece haber muchas
1067 probabilidades de que se siga manteniendo.
1069 LDC_ es lo opuesto; un compilador joven, nacido a mediados de 2007 como un
1070 proyecto personal y privado de Tomas Lindquist Olsen, que estuvo trabajando de
1071 forma privada en el proyecto hasta mediados de 2008, momento en que decide
1072 publicar el código mediante una licencia libre. Para ese entonces el
1073 compilador era todavía inestable y faltaban implementar varias cosas, pero el
1074 estado era lo suficientemente bueno como para captar varios colaboradores muy
1075 capaces, como `Christian Kamm`_ y Frits Van Bommel que rápidamente se
1076 convirtieron en parte fundamental del proyecto. El primer *release* (0.9) de
1077 una versión relativamente completa y estable fue a principios de 2009 que fue
1078 seguido por la versión 0.9.1 que como puntos más salientes agregó soporte para
1079 x86-64 y assembly embebido. El compilador tuvo y sigue teniendo un crecimiento
1080 excepcional. En la actualidad inclusive pasa más pruebas de estrés que el
1081 compilador de referencia DMD_. Como *back-end* utiliza LLVM_, otro proyecto
1082 joven y con una tasa de crecimiento muy alta.
1084 Además de estos compiladores hay varios otros experimentales, pero ninguno de
1085 ellos de calidad suficiente todavía. Por ejemplo hay un compilador
1086 experimental que emite *CIL* (*Common Intermediate Language*), el *bytecode*
1087 de `.NET`_, llamado DNet_. También hay un *front-end* escrito en D_, llamado
1090 Originalmente, dado que GDC_ estaba siendo mantenido y que LDC_ no existía,
1091 este trabajo iba a ser realizado utilizando GDC_ como compilador, dado que al
1092 ser `Software Libre`_ podía ser modificado de ser necesario. Finalmente,
1093 gracias a la excepcional tasa de crecimiento de LDC_ y al abandono de GDC_ se
1094 terminó desarrollando el trabajo utilizando LDC_.
1098 .. include:: links.rst
1100 .. vim: set ts=3 sts=3 sw=3 et tw=78 spelllang=es :