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 compilador de C++ que compilaba
27 a código nativo, y está fuertemente influenciado éste. Sin embargo toma muchos
28 conceptos de otros lenguajes de más alto nivel, como Java_ o incluso lenguajes
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 estar ante una versión estable y completa. Luego de liberarse se siguieron
48 agregando nuevas características al lenguaje hasta que se empezó el desarrollo
49 en paralelo de la versión 2.0 al introducirse el concepto de inmutabilidad
50 y funciones *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, abríendo 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, siendo esta etiqueta todavía un poco
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`_.
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_ 1.0
99 tiene dos bibliotecas base, una estándar pero de peor calidad y menos
100 mantenida y una alternativa de mayor calidad y apertura a la comunidad (pero
101 no estándar). El peor problema es que ambas son **incompatibles**, por lo que
102 un programa hecho con Tango_ no funciona con Phobos_ y viceversa (a menos que
103 el programador haya invertido una cantidad de tiempo considerable en
104 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 a solucionar
109 este problema ya que utiliza DRuntime_, un nuevo intento de Sean Kelly por
110 proveer una biblioteca *runtime* bien organizada y mantenida, que es una
111 adaptación de la biblioteca *runtime* de Tango_ a D 2.0. Si bien todavía
112 Tango_ no fue adaptada a D 2.0, se espera que cuando esto pase compartan la
113 misma biblioteca *runtime* permitiendo que bibliotecas y programas hechos para
114 Tango_ y Phobos_ 2.0 puedan coexistir sin problemas.
118 ----------------------------------------------------------------------------
120 D_ es un lenguaje de programación con sintaxis tipo C, multi-paradigma,
121 compilado, con *tipado* fuerte y estático, buenas capacidades tanto de
122 programación de bajo nivel (*system programming*) como de alto nivel. Es
123 compatible de forma binaria con C (se puede enlazar código objeto C con código
124 objeto D). Con estas características, D_ logra llenar un vacío importante que
125 hay entre lo lenguajes de alto bajo nivel y los de alto nivel [BKIP08]_. Si
126 bien tiene herramientas de muy bajo nivel, que por lo tanto son muy propensas
127 a errores, da una infinidad de mecanismos para evitar el uso de estas
128 herramientas a menos que sea realmente necesario. Además pone mucho énfasis
129 en la programación confiable, para lo cual provee muchos mecanismos para
130 detectar errores en los programas de forma temprana.
132 Si puede pensarse en C++ como un "mejor C", podría decirse que D_ es un "mejor
133 C++", ya que el objetivo del lenguaje es muy similar a C++, pero implementa
134 muchas características que jamás pudieron entrar en el estándar de C++ y lo
135 hace de una forma mucho más limpia, ya que no debe lidiar con problemas de
136 compatibilidad hacia atrás, y cuenta con la experiencia del camino recorrido
137 por C++, pudiendo extraer de él los mejores conceptos pero evitando sus
138 mayores problemas también.
140 Otra gran diferencia con C++ es la facilidad para ser analizado
141 sintácticamente (*parsing*), ya fue especialmente diseñado para ser sencillo
142 y a diferencia de C y C++ su gramática es independiente del contexto
143 (*context-free grammar*). Esto permite que D pueda ser compilado en pequeños
144 pasos bien separados:
147 2. Análisis sintáctico.
148 3. Análisis semántico.
150 5. Generación de código.
152 Esto favorece la creación de herramientas dada la facilidad de usar solamente
153 la cantidad de análisis necesario para cada herramienta (por ejemplo un editor
154 de textos puede tener hasta análisis sintáctico para proveer resaltado o un
155 entorno de desarrollo puede proveer herramientas de re-factorización de código
156 haciendo uso del análisis semántico).
158 Una de las características que nunca pudo entrar en el estándar de C++ es la
159 recolección de basura. D_ no comete el mismo error.
162 Características del lenguaje
163 ----------------------------------------------------------------------------
165 A continuación se enumeran las principales características de D_, agrupadas
166 por unidades funcional o paradigmas que soporta:
172 Programación genérica y meta-programación
173 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
175 La programación genérica se trata de la capacidad de poder desarrollar
176 algoritmos y estructuras independientes de los tipos que manipulan (pero de
177 forma segura o *type-safe*). Esto fue muy popularizado por C++ gracias a su
178 soporte de plantillas (*templates*) y luego otros lenguajes como Java_ y `C#`_
179 lo siguieron. Sin embargo otros lenguajes proveen formas más avanzadas de
180 programación genérica, gracias a sistemas de tipos más complejos (como
183 La meta-programación se refiere en general a la capacidad de un lenguaje para
184 permitir generar código dentro del mismo programa de forma automática. Esto
185 permite evitar duplicación de código y fue también muy popularizado por el
186 soporte de *templates* de C++, aunque muchos otros lenguajes tienen mejor
187 soporte de meta-programación, en especial los lenguajes dinámicos (como
190 D_ provee las siguientes herramientas para realizar programación genérica
193 ``if`` estático (``static if``)
194 puede verse como similar a la directiva del preprocesador de C/C++ ``#if``,
195 pero a diferencia de esto, en D_ el ``static if`` tiene acceso a todos los
196 símbolos del compilador (constantes, tipos, variables, etc).
200 static if ((void*).sizeof == 4)
201 pragma(msg, "32 bits");
203 Más información en http://www.digitalmars.com/d/1.0/version.html#staticif
205 Inferencia de tipos básica implícita y explícita (mediante ``typeof``)
206 si no se especifica un tipo al declarar una variable, se infiere del tipo
207 de su valor de inicialización.
211 static i = 5; // i es int
212 const d = 6.0; // d es double
213 auto s = "hola"; // s es string (que es un alias de char[])
216 http://www.digitalmars.com/d/1.0/declaration.html#AutoDeclaration
218 Mediante el uso de ``typeof`` se puede solicitar el tipo de una expresión
223 typeof(5 + 6.0) d; // d es double
225 Más información en http://www.digitalmars.com/d/1.0/declaration.html#typeof
227 Iteración sobre colecciones (``foreach``)
228 cualquier tipo de colección (arreglos estáticos y dinámicos, arreglos
229 asociativos, clases, estructuras o delegados) puede ser iterada mediante la
230 sentencia ``foreach``.
234 int[] a = [ 1, 2, 3 ];
240 clases y funciones pueden ser generalizadas. Esto permite desarrollar
241 algoritmos genéricos sin importar el tipo de los datos de entrada, siempre
242 y cuando todos los tipos tengan una *interfaz* común. Esto también es
243 conocido como *polimorfismo en tiempo de compilación*, y es la forma más
244 básica de programación genérica.
248 T sumar(T)(T x, T y) { return x + y; }
249 auto i = sumar!(int)(5, 6); // i == 11
250 auto f = sumar!(float)(5, 6); // j == 11.0f
252 Además se pueden definir bloques de declaraciones generalizadas (esto no
253 es posible en C++), permitiendo instanciar dicho bloque con parámetros
254 particulares. Esto sirve como un mecanismo para la reutilización de código,
255 ya que puede incluirse un mismo bloque en distintos lugares (por ejemplo
256 clases). Un bloque generalizado puede verse como una especie de módulo.
260 template bloque(T, U) {
265 bloque!(int, float).x = 5;
266 float f = bloque!(int, float).foo(7);
268 La utilidad más prominente de los bloques generalizados se da al
269 acompañarse de *mixins*.
271 Instanciación implícita de funciones generalizadas
272 el lenguaje es capaz de deducir los parámetros siempre que no hayan
277 auto i = sumar(5, 6); // i == 11
278 auto f = sumar(5.0f, 6.0f); // f == 11.0f
280 Especialización explícita y parcial de *templates*
281 la especialización de *templates* consiste, al igual que en C++, en proveer
282 una implementación especializada para un tipo de dato (o valor) de los
283 parámetros. Especialización parcial se refiere a la capacidad de
284 especializar un parámetro a través de un subtipo. Por ejemplo, se puede
285 especializar un *template* para cualquier tipo de puntero, o para cualquier
286 tipo de arreglo dinámico, sin necesidad de especificar el tipo al que
287 apunta dicho puntero o el tipo almacenado por el arreglo.
289 Ejemplo de especialización::
291 T sumar(T: int)(T x, T y) { return x + y + 1; }
292 auto i = sumar(5, 6); // i == 12
293 auto f = sumar(5.0f, 6.0f) // f == 11.0f
295 Ejemplo de especialización parcial::
297 T sumar(T: T*)(T x, T y) { return *x + *y; }
299 auto i = sumar(&x, &y); // i == 11
300 float v = 5.0f, w = 6.0f;
301 auto f = sumar(&v, &w); // f == 11.0f
303 Tipos, valores (incluyendo *strings*) y *templates* como parámetros
304 esto es otro bloque de construcción importantísimo para la programación
305 genérica en D, ya que combinando *templates* que toman *strings* como
306 parámetro en combinación con *string mixins* pueden hacerse toda clase de
311 template hash(string s, uint so_far=0) {
312 static if (s.length == 0)
315 const hash = hash!(s[1 .. length], so_far * 11 + s[0]);
317 string s = hash!("hola"); // calculado en tiempo de compilación
319 Cantidad de parámetros variables para *templates*
320 Esto permite implementar tuplas u otros algoritmos que inherentemente deben
321 tomar una cantidad variable de parámetros en tiempo de compilación.
325 double sumar(T...)(T t) {
331 double d = sumar(1, 2.0, 3.0f, 4l); // d == 10.0
333 *CTFE* (*compile-time function execution*)
334 si una función cumple ciertas reglas básicas (como por ejemplo no tener
335 efectos colaterales) puede ser ejecutada en tiempo de compilación en vez de
336 tiempo de ejecución. Esto permite hacer algunos cálculos que no cambian de
337 ejecución en ejecución al momento de compilar, mejorando el rendimiento
338 o permitiendo formas avanzadas de meta-programación. Esta característica se
339 vuelve particularmente útil al combinarse con *string mixins*.
343 int factorial(int n) {
347 return n * factorial(n - 1);
349 static int x = factorial(5); // calculado en tiempo de compilación
350 int x = factorial(5); // calculado en tiempo de ejecución
352 Esta característica es vital para evitar la duplicación de código.
354 *Mixins*, incluyendo *string mixins*
355 la palabra *mixin* tiene significados distintos en varios lenguajes de
356 programación. En D_ *mixin* significa tomar una secuencia arbitraria de
357 declaraciones e insertarla en el contexto (*scope*) actual. Esto puede
358 realizarse a nivel global, en clases, estructuras o funciones. Esto sirve
359 como un mecanismo para evitar duplicación de código que puede ser
360 introducida por la falta de herencia múltiple.
365 mixin bloque!(int, float);
369 float f = a.foo(a.x);
372 mixin bloque!(long, double);
376 double d = a.foo(a.x);
378 *String mixin* se refiere a la capacidad de *incrustar* un *string* que
379 contenga un fragmento de código en un programa como si este fragmento
380 hubiera sido escrito en el código fuente directamente por el programador.
381 Esto permite hacer manipulaciones arbitrariamente complejas en combinación
382 con funciones ejecutadas en tiempo de compilación.
386 string generar_sumar(string var_x, string var_y) {
387 return "return " ~ var_x ~ " + " ~ var_y ~ ";";
390 int sumar(int a, int b) {
391 mixin(generar_sumar!("a", b"));
394 Más información en http://www.digitalmars.com/d/1.0/mixin.html
397 las *expresiones ``is``* permiten la compilación condicional basada en las
398 características de un tipo. Esto se realiza en favor a una técnica
399 utilizada en C++ de realizar *pattern matching* sobre los parámetros de las
405 static if (is(T == class))
411 Esto provee además una forma simple de reflexión en tiempo de compilación.
414 http://www.digitalmars.com/d/1.0/expression.html#IsExpression
420 Programación de bajo nivel (*system programming*)
421 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
423 Por programación de bajo nivel nos referimos a la capacidad de un lenguaje de
424 manipular el hardware directamente, o al menos la memoria. C es probablemente
425 el lenguaje de bajo nivel más popular, seguido por C++.
427 D_ presenta muchas características de bajo nivel:
429 Compila a código de máquina nativo
430 no es interpretado ni necesita una máquina virtual como otros lenguajes de
431 más alto nivel como Java_, `C#`_, Python_, etc.
433 Provee acceso a *assembly*
434 por lo tanto, acceso directo al *hardware* y la posibilidad de utilizar
435 cualquier característica de éste que no esté disponible en el lenguaje.
437 Una ventaja sobre C y C++ es que el lenguaje *assembly* utilizado dentro de
438 D_ está especificado, por lo que se puede mantener la portabilidad entre
439 compiladores incluso cuando se utiliza *assembly* (mientras que no se
440 cambie de arquitectura, por supuesto).
443 al igual que C y C++, D_ provee la flexibilidad del uso de ``goto``.
446 soporta todos los tipos de C y es ABI [#abi]_ compatible con éste. Esto
447 permite enlazar archivos objeto estándar de C y D_ en un mismo programa.
448 Además permite interoperar con C a través de ``extern (C)``.
450 .. [#abi] Interfaz de Aplicación Binaria (del inglés *Application Binary
455 extern (C) printf(const char* format, ...);
456 printf("3 + 5 == %d\n", 3 + 5); // llama al printf de C
458 Manejo de memoria explícito
459 permite asignar estructuras en el *stack* o en el *heap*, haciendo uso de
460 los servicios del sistema operativo o la biblioteca estándar de C.
462 Objetos y arreglos *livianos*
463 por objetos *livianos* se entiende no-polimórficos. Es decir, un
464 agrupamiento de variables análogo al ``struct`` de C, sin tabla virtual ni
465 otro tipo de *overhead*. Los arreglos *livianos* son arreglos estáticos
466 como en C, cuyo tamaño es fijo, también sin ningún tipo de *overhead* como
467 C. Además puede asignarse un arreglo dinámicamente usando ``malloc()``
468 y utilizar el operador ``[]`` para accederlo.
470 Esto también permite interoperar con C, ya que pueden definirse ``structs``
471 y arreglos que pueden ser intercambiados con dicho lenguaje sin problemas.
480 void* malloc(size_t);
481 size_t strlen(const char *);
482 int gettimeofday(timeval *, void *);
484 char* s = cast(char*) malloc(2);
487 size_t l = strlen(s); // l == 1
489 gettimeofday(&tv, null);
492 la :ref:`d_generic` permite realizar muchas optimizaciones ya que se
493 resuelve en tiempo de compilación y por lo tanto aumenta el rendimiento en
496 Número de punto flotante de 80 bits
497 El tipo ``real`` de D_ tiene precisión de 80 bits si la plataforma lo
498 soporta (por ejemplo en i386).
500 Control de alineación de miembros de una estructura
501 Mediante ``align`` se puede especificar la alineación a tener en una
507 struct paquete_de_red {
511 // paquete_de_red.sizeof == 3
517 Programación de alto nivel
518 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
520 Programación de alto nivel se refiere a construcciones más avanzadas que una
521 sentencia para iterar; expresiones con una semántica más ricas que proveen de
522 mayor expresividad al programador o le permiten focalizarse de mejora manera
523 en los algoritmos independizándose del *hardware* o de como funciona una
524 computadora. Es exactamente el opuesto a :ref:`d_low_level`.
526 En general estas características tienen como efecto secundario una mejora de la
527 productividad de los programadores. D_ adopta herramientas de muchos lenguajes
528 de alto nivel, como Java_ y Python_, por ejemplo:
530 Manejo automático de memoria
531 al igual que C/C++ y prácticamente cualquier lenguaje imperativo maneja
532 automáticamente el *stack*, pero a diferencia de la mayoría de los
533 lenguajes de bajo nivel, D_ permite manejar el *heap* de manera automática
534 también a través de un *recolector de basura*.
536 Sistema de paquetes y módulos (similar a Java_ o Python_)
537 un módulo es una unidad que agrupa clases, funciones y cualquier otra
538 construcción de lenguaje. Un paquete es una agrupación de módulos. D_
539 asocia un módulo a un archivo fuente (y un archivo objeto cuando éste es
540 compilado) y un paquete a un directorio. A diferencia de C/C++ no necesita
541 de un preprocesador para incluir declaraciones de otros *módulos* (en C/C++
542 no existe el concepto de módulo, solo de unidades de compilación).
563 f(); // ejecuta b.f()
565 Funciones y delegados
566 las funciones pueden ser sobrecargadas (funciones con el mismo nombre pero
567 distinta cantidad o tipo de parámetros), pueden especificarse argumentos de
568 entrada, salida o entrada/salida, argumentos por omisión o argumentos
569 evaluados de forma perezosa (*lazy*). Además pueden tener una cantidad de
570 argumentos variables pero manteniendo información de tipos (más seguro que
573 Los *delegados* son punteros a función con un contexto asociado. Este
574 contexto puede ser un objeto (en cuyo caso la función es un método) o un
575 *stack frame* (en cuyo caso la función es una función anidada).
577 Además de esto los delegados son ciudadanos de primera clase
578 [#1stclasscity]_, disponiendo de forma literal (delegado anónimo), lo que
579 permite construcciones de alto nivel muy conveniente. Los argumentos
580 evaluados de forma perezosa no son más que un delegado que se ejecuta solo
583 .. [#1stclasscity] Por ciudadano de primera clase se entiende que se trata
584 de un tipo soportado por completo por el lenguaje, disponiendo de
585 expresiones literales anónimas, pudiendo ser almacenados en variables,
586 estructuras de datos, teniendo una identidad intrínseca, más allá de un
587 nombre dado, etc. En realidad los arreglos asociativos no pueden ser
588 expresados como literales anónimos pero sí tienen una sintaxis especial
589 soportada directamente por el lenguaje.
593 bool buscar(T[] arreglo, T item, bool delegate(T x, T y) igual) {
606 bool encontrado = buscar(personas, p,
607 (Persona x, Persona y) {
608 return x.nombre == y.nombre;
612 Arreglos *dinámicos* y arreglos asociativos
613 los arreglos *dinámicos* son arreglos de longitud variable manejados
614 automáticamente por el lenguaje (análogos al ``std::vector`` de C++).
615 Soportan concatenación (a través del operador ``~``), rebanado o *slicing*
616 (a través del operador ``[x..y]``) y chequeo de límites (*bound checking*).
618 Los arreglos asociativos (también conocidos como *hashes* o diccionarios)
619 también son provistos por el lenguaje.
621 Ambos son ciudadanos de primera clase, disponiendo de forma literal.
625 int[] primos = [ 2, 3, 5, 7, 11, 13, 17, 19 ];
626 primos ~= [ 23, 29 ];
627 auto menores_que_10 = primos[0..4]; // [ 2, 3, 5, 7 ]
629 agenda["Pepe"] = 5555_1234;
632 al igual que los delegados y arreglos dinámicos y asociativos, los
633 *strings* son ciudadanos de primera clase, teniendo forma literal y siendo
634 codificados en UTF-8/16/32. Son un caso particular de arreglo dinámico y es
635 posible utilizarlos en sentencias ``switch``/``case``.
648 ``typedef`` y ``alias``
649 el primero define un nuevo tipo basado en otro. A diferencia de C/C++ el
650 tipo original no puede ser implícitamente convertido al tipo nuevo (excepto
651 valores literales), pero la conversión es válida en el otro sentido
652 (similar a los ``enum`` en C++). Por el contrario, ``alias`` es análogo al
653 ``typedef`` de C/C++ y simplemente es una forma de referirse al mismo tipo
654 con un nombre distinto.
663 foo(i); // error, no compila
668 Documentación embebida
669 D_ provee un sistema de documentación embebida, análogo a lo que proveen
670 Java_ o Python_ en menor medida. Hay comentarios especiales del código que
671 pueden ser utilizados para documentarlo de forma tal que luego el
672 compilador pueda extraer esa información para generar un documento.
674 Más información en http://www.digitalmars.com/d/1.0/ddoc.html
677 D_ soporta números complejos como ciudadanos de primera clase. Soporta
678 forma literal de números imaginarios y complejos.
684 cfloat c = re + im; // c == 1.0 + 5.0i
688 Programación orientada a objetos
689 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
691 La orientación a objetos es probablemente el paradigma más utilizado en la
692 actualidad a la hora de diseñar e implementar un programa. D_ provee muchas
693 herramientas para soportar este paradigma de forma confiable. Entre las
694 características más salientes se encuentran:
697 objetos polimórficos como los de cualquier lenguaje con orientación real
698 a objetos. Estos objetos poseen una tabla virtual para despacho dinámico,
699 todos los métodos son virtuales a menos que se indique lo contrario
700 y tienen semántica de referencia [#drefsem]_. Estos objetos tienen un
701 *overhead* comparados a los objetos *livianos* pero aseguran una semántica
702 segura para trabajar con orientación a objetos, evitando problemas con los
703 que se enfrenta C++ (como *slicing* [#dslicing]_) debido a que permite
704 semántica por valor [#dvalsem]_.
706 .. [#drefsem] Semántica de referencia significa que el tipo es tratado como
707 si fuera un puntero. Nunca se hacen copias del objeto, siempre se pasa
709 .. [#dslicing] Este problema se da en C++ cuando se pasa una clase derivada
710 a una función que acepta una clase base por valor como parámetro. Al
711 realizarse una copia de la clase con el constructor de copia de la clase
712 base, se pierden (o *rebanan*) los atributos de la clase derivada, y la
713 información de tipos en tiempo de ejecución (*RTTI*).
714 .. [#dvalsem] Semántica de valor significa que el tipo es tratado como si
715 fuera un valor concreto. En general se pasa por valor y se hacen copias
716 a menos que se utilice explícitamente un puntero.
718 D_ además soporta tipos de retorno covariantes para funciones virtuales.
719 Esto significa que una función sobreescrita por una clase derivada puede
720 retornar un tipo que sea derivado del tipo retornado por la función
721 original sobreescrita.
729 A test() { return null; }
733 B test() { return null; } // sobreescribe y es covariante con Foo.test()
736 Más información en http://www.digitalmars.com/d/1.0/function.html
739 D_ no soporta herencia múltiple pero sí interfaces. Una interfaz es
740 básicamente una tabla virtual, una definición de métodos virtuales que debe
741 proveer una clase. Las interfaces no proveen una implementación de dichos
742 métodos, ni pueden tener atributos. Esto simplifica mucho el lenguaje y no
743 se pierde flexibilidad porque puede conseguirse el mismo efecto de tener
744 herencia múltiple a través de interfaces y *mixins* para proveer una
745 implementación o atributos en común a varias clases que implementan la
748 Sobrecarga de operadores
749 la sobrecarga de operadores permite que un objeto tenga una sintaxis
750 similar a un tipo de dato nativo. Esto es muy importante además para la
751 programación genérica.
754 al igual que C (con respecto a ``struct``) y C++, pueden anidarse clases
755 dentro de clases. D_ sin embargo provee la posibilidad de acceder
756 a atributos de la instancia exterior desde la anidada.
764 return m; // ok, puede acceder a un miembro de Exterior
769 Esto tiene un pequeño *overhead* ya que la clase ``Anidada`` debe guardar
770 un puntero a la clase ``Exterior``. Si no se necesita este comportamiento
771 es posible evitar este *overhead* utilizando ``static``, en cuyo caso solo
772 puede acceder a atributos estáticos de la clase ``Exterior``.
779 static class Anidada {
781 //return m; // error, miembro de Exterior
782 return n; // ok, miembro estático de Exterior
788 Propiedades (*properties*)
789 en D_ se refiere a funciones miembro que pueden ser tratadas
790 sintácticamente como campos de esa clase/estructura.
795 int data() { return _data; } // propiedad de lectura
796 int data(int value) { return _data = value; } // de escritura
800 f.data = 1; // llama a f.data(1)
801 int i = f.data; // llama a f.data()
803 Además tipos nativos, clases, estructuras y expresiones tienen
804 *properties* predefinidos, por ejemplo:
807 tamaño ocupado en memoria (ejemplo: ``int.sizeof`` -> 4).
810 valor de inicialización por omisión (ejemplo: ``float.init`` -> *NaN*
813 .. [#dnan] Del inglés *Not A Number*, es un valor especial que indica que
814 estamos ante un valor inválido.
817 representación textual del símbolo o expresión (ejemplo:
818 ``(1+2).stringof`` -> ``"1 + 2"``).
821 representación textual del tipo *mutilado* [#dmangle]_.
823 .. [#dmangle] *Name mangling* es el nombre dado comunmente a una técnica
824 necesaria para poder sobrecargar nombres de símbolos. Consiste en
825 codificar los nombres de las funciones tomando como entrada el nombre de
826 la función y la cantidad y tipo de parámetros, asegurando que dos
827 funciones con el mismo nombre pero distintos parámetros (sobrecargada)
828 tengan nombres distintos.
831 alineación de una estructura o tipo.
833 Estos son solo los *properties* predefinidos para todos los tipos, pero hay
834 una cantidad considerable de *properties* extra para cada tipo.
836 Más información sobre *properties* de clases en
837 http://www.digitalmars.com/d/1.0/property.html#classproperties y sobre
838 *properties* predefinidos en
839 http://www.digitalmars.com/d/1.0/property.html
845 Programación confiable
846 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
848 Programación confiable se refiere a las capacidades o facilidades que provee
849 el lenguaje para evitar fallas de manera temprano (o la capacidad de evitar
850 que ciertas fallas puedan existir directamente). D_ presta particular atención
851 a esto y provee las siguientes herramientas:
854 D_ soporta excepciones de manera similar a Java_: provee ``try``, ``catch``
855 y ``finally``. Esto permite que los errores difícilmente pasen
856 silenciosamente sin ser detectados.
859 es una condición que debe cumplirse siempre en un programa, como un chequeo
860 de integridad. Esto es muy utilizado en C/C++, donde ``assert()`` es una
861 *macro* que solo se compila cuando la *macro* ``NDEBUG`` no está definida.
862 Esto permite eliminar los chequeos de integridad del programa, que pueden
863 ser costosos, para versiones que se suponen estables.
865 D_ lleva este concepto más allá y hace al ``assert`` parte del lenguaje.
866 Si una verificación no se cumple, lanza una excepción. El ``assert`` no es
867 compilado cuando se utiliza una opción del compilador.
871 File f = open("archivo");
875 el diseño por contrato es un concepto introducido por el lenguaje Eiffel_
876 a mediados/finales de los '80. Se trata de incorporar en el lenguaje las
877 herramientas para poder aplicar verificaciones formales a las interfaces de
880 D_ implementa las siguientes formas de diseño por contrato (todas se
881 ejecutan siempre y cuando no se compile en modo *release*, de manera de no
882 sacrificar rendimiento cuando es necesario):
884 Pre y post condiciones
887 double raiz_cuadrada(double x)
888 in { // pre-condiciones
891 out (resultado) { // post-condiciones
892 assert (resultado >= 0.0);
894 assert (resultado < x);
896 assert (resultado > x);
898 assert (resultado == 1);
904 Invariantes de representación
905 La invariante de representación es un método de una clase o estructura
906 que es verificada cuando se completa su construcción, antes de la
907 destrucción, antes y después de ejecutar cualquier función miembro
908 pública y cuando se lo requiere de forma explícita utilizando
917 assert(1 <= dia && dia <= 31);
918 assert(0 <= hora && hora < 24);
922 Más información en http://www.digitalmars.com/d/1.0/dbc.html
925 es posible incluir pequeñas pruebas unitarias en el lenguaje. Éstas son
926 ejecutadas (cuando no se compila en modo *release*) al comenzar el
927 programa, antes de que la función ``main()``.
934 assert (fecha.dia == 5);
938 Orden de construcción estática
939 a diferencia de C++, D_ garantiza el orden de inicialización de los
940 módulos. Si bien en C++ no hay módulos si no unidades de compilación, es
941 posible que se ejecute código antes del ``main()`` en C++, si hay, por
942 ejemplo, instancias globales con un constructor definido. C++ no garantiza
943 un orden de inicialización, lo que trae muchos problemas. En D_ se define
944 el orden de inicialización y es el mismo orden en que el usuario importa
947 Inicialización garantizada
948 todas las variables son inicializadas por el lenguaje (a menos que el
949 usuario pida explícitamente que no lo sean). Siempre que sea posible se
950 elijen valores de inicialización que permitan saber al programador que la
951 variable no fue inicializada explícitamente, de manera de poder detectar
952 errores de manera temprana.
956 double d; // inicializado a NaN
957 int x; // inicializado a 0
958 Fecha f; // inicializado a null
959 byte[5] a; // inicializados todos los valores a 0
960 long l = void; // NO inicializado (explícitamente)
962 *RAII* (*Resource Adquisition Is Initialization*)
963 es una técnica muy utilizada en C++ que consiste en reservar recursos por
964 medio de la construcción de un objeto y liberarlos cuando se libera éste.
965 Al llamarse al destructor de manera automática cuando se sale del *scope*,
966 se asegura que el recurso será liberado también.
968 Esta técnica es la base para desarrollar código seguro en cuanto
969 a excepciones (*exception-safe*) [SUTT99]_.
971 En D_ no es tan común utilizar *RAII* dada la existencia del recolector de
972 basura (en la mayoría de los casos el recurso a administrar es
973 sencillamente memoria). Sin embargo en los casos en donde es necesario,
974 puede utilizarse *RAII* mediante la utilización de la palabra reservada
975 ``scope``, que limita la vida de un objeto un bloque de código.
980 this() { /* adquiere recurso */ }
981 ~this() { /* libera recurso */ }
984 scope Archivo archivo = new Archivo;
986 } // en este punto se llama al destructor de archivo
988 Guardias de bloque (*scope guards*)
989 además de poder limitar la vida de una instancia a un *scope*, es posible
990 especificar un bloque de código arbitrario a ejecutar al abandonar un
991 *scope*, ya sea cuando se sale del *scope* normalmente o por una falla.
998 lock.unlock(); // ejecutado siempre que salga de f()
999 auto trans = new Transaccion;
1001 trans.commit(); // ejecutado si sale con "return"
1003 trans.rollback(); // ejecutado si sale por una excepción
1005 throw Exception("error"); // lock.unlock() y trans.rollback()
1006 else if (otra_condicion)
1007 return 5; // lock.unlock() y trans.commit()
1008 return 0; // lock.unlock() y trans.commit()
1011 Esta es una nueva forma de poder escribir código *exception-safe*, aunque
1012 el programador debe tener un poco más de cuidado de especificar las
1013 acciones a ejecutar al finalizar el *scope*.
1015 Primitivas de sincronización de hilos
1016 la programación multi-hilo está directamente soportada por el lenguaje,
1017 y se provee una primitiva de sincronización al igual que Java_. La palabra
1018 reservada ``synchronized`` puede aparecer como modificador de métodos (en
1019 cuyo caso se utiliza un *lock* por clase para sincronizar) o como una
1020 sentencia, en cuyo caso se crea un *lock* global por cada bloque
1021 ``synchronized`` a menos que se especifique sobre qué objeto realizar la
1022 sincronización. Por ejemplo::
1025 synchronized void bar() { /* cuerpo */ }
1032 synchronized (this) { /* cuerpo */ }
1038 ----------------------------------------------------------------------------
1040 Hay, hasta el momento, 3 compiladores de D_ de buena calidad: DMD_, GDC_
1043 DMD_ es el compilador de referencia, escrito por `Walter Bright`_. El
1044 *front-end* [#frontend]_ de este compilador ha sido liberado bajo licencia
1045 Artistic_/GPL_ y es utilizado por los otros dos compiladores, por lo tanto en
1046 realidad hay solo un compilador disponible con 3 *back-ends* [#backend]_
1049 .. [#frontend] *Front-end* es la parte del compilador encargada de hacer el
1050 análisis léxico, sintáctico y semántico del código fuente, generando una
1051 representación intermedia que luego el *back-end* convierte a código de
1054 .. [#backend] El *back-end* es la parte del compilador encargada de convertir
1055 la representación intermedia generada por el *front-end* a código de
1058 Con `DMD 1.041`__ se publicó el código fuente completo del compilador, pero
1059 con una licencia muy restrictiva para uso personal, por lo que el único efecto
1060 logrado por esto es que la gente pueda mandar parches o correcciones del
1061 compilador pero no lo convierte en `Software Libre`_, siendo el único de los
1062 3 compiladores que no tiene esta característica.
1064 __ http://www.digitalmars.com/d/1.0/changelog.html#new1_041
1066 El compilador GDC_ es el *front-end* de DMD_ utilizando al compilador GCC_
1067 como *back-end*. Fue un muy buen compilador pero en la actualidad está
1068 abandonado. No hay un *release* desde agosto de 2007 y no hay actualizaciones
1069 serias del código desde mediados de 2008, por lo que no parece haber muchas
1070 probabilidades de que se siga manteniendo.
1072 LDC_ es lo opuesto; un compilador joven, nacido a mediados de 2007 como un
1073 proyecto personal y privado de Tomas Lindquist Olsen, que estuvo trabajando de
1074 forma privada en el proyecto hasta mediados de 2008, momento en que decide
1075 publicar el código mediante una licencia libre. Para ese entonces el
1076 compilador era todavía inestable y faltaban implementar varias cosas, pero el
1077 estado era lo suficientemente bueno como para captar varios colaboradores muy
1078 capaces, como `Christian Kamm`_ y Frits Van Bommel que rápidamente se
1079 convirtieron en parte fundamental del proyecto. El primer *release* (0.9) de
1080 una versión relativamente completa y estable fue a principios de 2009 que fue
1081 seguido por la versión 0.9.1 que como puntos más salientes agregó soporte para
1082 x86-64 y assembly embebido. El compilador tuvo y sigue teniendo un crecimiento
1083 excepcional. En la actualidad inclusive pasa más pruebas de estrés que el
1084 compilador de referencia DMD_. Como *back-end* utiliza LLVM_, otro proyecto
1085 joven y con una tasa de crecimiento muy alta.
1087 Además de estos compiladores hay varios otros experimentales, pero ninguno de
1088 ellos de calidad suficiente todavía. Por ejemplo hay un compilador
1089 experimental que emite *CIL* (*Common Intermediate Language*), el *bytecode*
1090 de `.NET`_, llamado DNet_. También hay un *front-end* escrito en D_, llamado
1093 Originalmente, dado que GDC_ estaba siendo mantenido y que LDC_ no existía,
1094 este trabajo iba a ser realizado utilizando GDC_ como compilador, dado que al
1095 ser `Software Libre`_ podía ser modificado de ser necesario. Finalmente,
1096 gracias a la excepcional tasa de crecimiento de LDC_ y al abandono de GDC_ se
1097 terminó desarrollando el trabajo utilizando LDC_.
1101 .. include:: links.rst
1103 .. vim: set ts=3 sts=3 sw=3 et tw=78 spelllang=es :