]> git.llucax.com Git - z.facultad/75.00/informe.git/blob - source/d.rst
Terminar capítulo Recolección de basura en D
[z.facultad/75.00/informe.git] / source / d.rst
1
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
6
7
8 .. _d_lang:
9
10 El lenguaje de programación D
11 ============================================================================
12
13
14 Historia
15 ----------------------------------------------------------------------------
16
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.
21
22 __ `D 1.0`_
23 __ `D 2.0`_
24
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
29 dinámicos como Perl_.
30
31 El origen del lenguaje está plasmado en su sitio web, en donde se cita:
32
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.
37
38 Esto podría traducirse como:
39
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.
45
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).
51
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_.
57
58 A partir de este momento la versión 1.0 quedó *teóricamente* congelada,
59 introduciendo solo cambios que arreglen errores (*bug fixes*), introduciendo
60 todos las nuevas características solamente en la versión 2.0 del lenguaje. La
61 realidad es que se hicieron cambios incompatibles a la versión 1.0 del
62 lenguaje en reiteradas ocasiones, pero se fue tendiendo a cada vez introducir
63 menos cambios incompatibles. Sin embargo al día de hoy el compilador de
64 referencia sigue teniendo algunas características presentes en la
65 especificación del lenguaje sin implementar, por lo que todavía no hay una
66 implementación completa de la versión 1.0 del lenguaje, siendo esta etiqueta
67 todavía un poco arbitraria.
68
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.
74
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.
87
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`_.
96
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 2 bibliotecas base, una estándar pero de peor calidad y menos mantenida
100 y una alternativa de mayor calidad y apertura a la comunidad (pero no
101 estándar). El peor problema es que ambas son **incompatibles**, por lo que un
102 programa hecho con Tango_ no funciona con Phobos_ y viceversa (a menos que el
103 programador haya invertido una cantidad de tiempo no trivial en asegurarse de
104 que funcione con ambas).
105
106 Esto hace que la compatibilidad de programas y bibliotecas esté muy
107 fragmentada entre las 2 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.
115
116
117 Descripción general
118 ----------------------------------------------------------------------------
119
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.
131
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.
139
140 Otra gran diferencia con C++ es la facilidad para ser analizado
141 gramaticalmente (*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:
145
146 1. Análisis léxico.
147 2. Análisis sintáctico.
148 3. Análisis semántico.
149 4. Optimizaciones.
150 5. Generación de código.
151
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).
157
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.
160
161
162 Características del lenguaje
163 ----------------------------------------------------------------------------
164
165 A continuación se enumeran las principales características de D_, agrupadas
166 por unidades funcional o paradigmas que soporta:
167
168
169
170 .. _d_generic:
171
172 Programación genérica y meta-programación
173 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
174
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
181 Haskell_).
182
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
188 Python_).
189
190 D_ provee las siguientes herramientas para realizar programación genérica
191 y meta-programación:
192
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).
197
198    Ejemplo::
199
200       static if ((void*).sizeof == 4)
201          pragma(msg, "32 bits");
202
203    Más información en http://www.digitalmars.com/d/1.0/version.html#staticif
204
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 inicializador.
208
209    Ejemplo::
210
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[])
214
215    Más información en
216    http://www.digitalmars.com/d/1.0/declaration.html#AutoDeclaration
217
218    Mediante el uso de ``typeof`` se puede solicitar el tipo de una expresión
219    arbitraria.
220
221    Ejemplo::
222
223       typeof(5 + 6.0) d; // d es double
224
225    Más información en http://www.digitalmars.com/d/1.0/declaration.html#typeof
226
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``.
231
232    Ejemplo::
233
234       int[] a = [ 1, 2, 3 ];
235       int total = 0;
236       foreach (i; a)
237          total += i;
238
239 *Templates*:
240    clases y funciones pueden ser parametrizadas. 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.
245
246    Ejemplo::
247
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
251
252    Además se pueden definir bloques de declaraciones parametrizados (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 parametrizado puede verse como una especie de módulo.
257
258    Ejemplo::
259
260       template bloque(T, U) {
261          T x;
262          U foo(T y);
263       }
264
265       bloque!(int, float).x = 5;
266       float f = bloque!(int, float).foo(7);
267
268    La utilidad más prominente de los bloques parametrizados se da al
269    acompañarse de *mixins*.
270
271 Instanciación implícita de funciones parametrizadas:
272    el lenguaje es capaz de deducir los parámetros siempre que no hayan
273    ambigüedades
274
275    Ejemplo::
276
277       auto i = sumar(5, 6);          // i == 11
278       auto f = sumar(5.0f, 6.0f); // f == 11.0f
279
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.
288
289    Ejemplo de especialización::
290
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
294
295    Ejemplo de especialización parcial::
296
297       T sumar(T: T*)(T x, T y) { return *x + *y; }
298       int x = 5, y = 6;
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
302
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
307    meta-programas.
308
309    Ejemplo::
310
311       template hash(string s, uint so_far=0) {
312          static if (s.length == 0)
313             const hash = sofar;
314          else
315             const hash = hash!(s[1 .. length], sofar * 11 + s[0]);
316       }
317       string s = hash!("hola"); // calculado en tiempo de compilación
318
319 Cantidad de parámetros variables para *templates*:
320    Esto permite implementar tuplas u otros algoritmos que inherentemente deben
321    tomar parámetros variables en tiempo de compilación.
322
323    Ejemplo::
324
325       double sumar(T...)(T t) {
326          double res = 0.0;
327          foreach (x; t)
328             res += x;
329          return res;
330       }
331       double d = sumar(1, 2.0, 3.0f, 4l); // d == 10.0
332
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 la performance
338    o permitiendo formas avanzadas de metaprogramación. Esta característica se
339    vuelve particularmente útil al combinarse con *string mixins*.
340
341    Ejemplo::
342
343       int factorial(int n) {
344          if (n == 1)
345             return 1;
346          else
347             return n * factorial(n - 1);
348       }
349       static int x = factorial(5); // calculado en tiempo de compilación
350       int x = factorial(5); // calculado en tiempo de ejecución
351
352    Esta característica es vital para evitar la duplicación de código.
353
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.
361
362    Ejemplo::
363
364       class A {
365          mixin bloque!(int, float);
366       }
367       A a = new A;
368       a.x = 5;
369       float f = a.foo(a.x);
370
371       class B {
372          mixin bloque!(long, double);
373       }
374       B b = new B;
375       b.x = 5l;
376       double d = a.foo(a.x);
377
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.
383
384    Ejemplo::
385
386       string generar_sumar(string var_x, string var_y) {
387          return "return " ~ var_x ~ " + " ~ var_y ~ ";";
388       }
389
390       int sumar(int a, int b) {
391          mixin(generar_sumar!("a", b"));
392       }
393
394    Más información en http://www.digitalmars.com/d/1.0/mixin.html
395
396 Expresiones ``is``:
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
400    plantillas.
401
402    Ejemplo::
403
404       T foo(T)(T x) {
405          static if (is(T == class))
406             return new T;
407          else
408             return T.init;
409       }
410
411    Esto provee además una forma simple de reflexión en tiempo de compilación.
412
413    Más información en
414    http://www.digitalmars.com/d/1.0/expression.html#IsExpression
415
416
417
418 .. _d_low_level:
419
420 Programación de bajo nivel (*system programming*)
421 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
422
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++.
426
427 D_ presenta muchas características de bajo nivel:
428
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.
432
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.
436
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).
441
442 ``goto``:
443    al igual que C y C++, D_ provee la flexibilidad del uso de ``goto``.
444
445 Compatibilidad con C:
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)``.
449
450    .. [#abi] Interfaz de Aplicación Binaria (del inglés *Application Binary
451       Interface*).
452
453    Ejemplo::
454
455       extern (C) printf(const char* format, ...);
456       printf("3 + 5 == %d\n", 3 + 5); // llama al printf de C
457
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.
461
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.
469
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.
472
473    Ejemplo::
474
475       struct timeval {
476          time_t         tv_sec;
477          suseconds_t tv_usec;
478       }
479       extern (C) {
480          void* malloc(size_t);
481          size_t strlen(const char *);
482          int gettimeofday(timeval *, void *);
483       }
484       char* s = cast(char*) malloc(2);
485       s[0] = 'C';
486       s[1] = '\0';
487       size_t l = strlen(s); // l == 1
488       timeval tv;
489       gettimeofday(&tv, null);
490
491 Rendimiento:
492    la :ref:`d_generic` permite realizar muchas optimizaciones ya que se
493    resuelve en tiempo de compilación y por lo tanto aumentando la
494    *performance* en la ejecución.
495
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).
499
500 Control de alineación de miembros de una estructura:
501    Mediante ``align`` se puede especificar la alineación a tener en una
502    estructura.
503
504    Ejemplo::
505
506       align (1)
507       struct paquete_de_red {
508          char   tipo;
509          short valor;
510       }
511       // paquete_de_red.sizeof == 3
512
513
514
515 .. _d_high_level:
516
517 Programación de alto nivel
518 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
519
520 Programa de alto nivel se refiere a construcciones más avanzadas que un loop.
521 Expresiones semánticamente más ricas que permiten mayor expresividad al
522 programador o le permiten focalizarse de mejora manera en los algoritmos
523 independizándose del *hardware* o de como funciona una computadora. Es
524 exactamente el opuesto a :ref:`d_low_level`.
525
526 En general estas características tiene 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:
529
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 *recolección de basura*.
535
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).
543
544    Ejemplo:
545
546    ``a.d``::
547
548       module a;
549       void f() {}
550
551    ``b.d``::
552
553       module b;
554       void f() {}
555
556    ``c.d``::
557
558          module c;
559          import a;
560          import b: f;
561          a.f();
562          b.f();
563          f(); // ejecuta b.f()
564
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
571    C/C++).
572
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).
576
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
581    cuando es necesario.
582
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.
590
591    Ejemplo::
592
593       bool buscar(T[] arreglo, T item, bool delegate(T x, T y) igual) {
594          foreach (t, arreglo)
595             if (igual(t, elemento))
596                return true;
597          return false;
598       }
599       struct Persona {
600          string nombre;
601       }
602       Persona[] personas;
603       // llenas personas
604       Persona p;
605       p.nombre = "Carlos";
606       bool encontrado = buscar(personas, p,
607                                        (Persona x, Persona y) {
608                                           return x.nombre == y.nombre;
609                                        }
610                                  );
611
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*).
617
618    Los arreglos asociativos (también conocidos como *hashes* o diccionarios)
619    también son provistos por el lenguaje.
620
621    Ambos son ciudadanos de primera clase, disponiendo de forma literal.
622
623    Ejemplo::
624
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 ]
628       int[string] agenda;
629       agenda["Pepe"] = 5555_1234;
630
631 *Strings*:
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``.
636
637    Ejemplo::
638
639       string s = "árbol";
640
641       switch (s) {
642          case "árbol":
643             s = "tree";
644          default:
645             s = "";
646       }
647
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.
655
656    Ejemplo::
657
658       typedef int tipo;
659       int foo(tipo x) {}
660       tipo t = 10;
661       int i = 10;
662       foo(t);
663       foo(i); // error, no compila
664       alias tipo un_alias;
665       un_alias a = t;
666       foo(a);
667
668 Documentación embebida:
669    D_ provee un sistema de documentación embebida, análogo a lo que provee
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.
673
674    Más información en http://www.digitalmars.com/d/1.0/ddoc.html
675
676 Números complejos:
677    D_ soporta números complejos como ciudadanos de primera clase. Soporta
678    forma literal de números imaginarios y complejos.
679
680    Ejemplo::
681
682       ifloat im = 5.0i;
683       float   re = 1.0;
684       cfloat c   = re + im; // c == 1.0 + 5.0i
685
686
687
688 Programación orientada a objetos
689 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
690
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:
695
696 Objetos *pesados*:
697    objetos polimórficos como los de cualquier lenguaje con orientación real
698    a objetos. Estos objetos poseen una tabla virtual para *dispatch* 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]_.
705
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
708       por referencia.
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.
717
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.
722
723    Ejemplo::
724
725       class A { }
726       class B : A { }
727
728       class Foo {
729          A test() { return null; }
730       }
731
732       class Bar : Foo {
733          B test() { return null; } // sobreescribe y es covariante con Foo.test()
734       }
735
736    Más información en http://www.digitalmars.com/d/1.0/function.html
737
738 Interfaces:
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
746    misma interfaz.
747
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.
752
753 Clases anidadas:
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.
757
758    Ejemplo::
759
760       class Exterior {
761          int m;
762          class Anidada {
763             int foo() {
764                return m; // ok, puede acceder a un miembro de Exterior
765             }
766          }
767       }
768
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``.
773
774    Ejemplo::
775
776       class Exterior {
777          int m;
778          static int n;
779          static class Anidada {
780             int foo() {
781                //return m; // error, miembro de Exterior
782                return n; // ok,   miembro estático de Exterior
783             }
784          }
785       }
786
787
788 Propiedades (*properties*):
789    en D_ se refiere a funciones miembro que pueden ser tratadas
790    sintácticamente como campos de esa clase/estructura.
791
792    Ejemplo::
793
794       class Foo {
795          int data() { return _data; } // propiedad de lectura
796          int data(int value) { return _data = value; } // de escritura
797          private int _data;
798       }
799       Foo f = new Foo;
800       f.data = 1;       // llama a f.data(1)
801       int i = f.data; // llama a f.data()
802
803    Además tipos nativos, clases, estructuras y expresiones tienen
804    *properties* predefinidos, por ejemplo:
805
806    ``sizeof``:
807       tamaño ocupado en memoria (ejemplo: ``int.sizeof`` -> 4).
808
809    ``init``:
810       valor de inicialización por omisión (ejemplo: ``float.init`` -> *NaN*
811       [#dnan]_).
812
813    .. [#dnan] Del inglés *Not A Number*, es un valor especial que indica que
814       estamos ante un valor inválido.
815
816    ``stringof``:
817       representación textual del tipo (ejemplo: ``(1+2).stringof`` -> ``"1
818       + 2"``).
819
820    ``mangleof``:
821       representación textual del tipo *mutilado* [#dmangle]_.
822
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.
829
830    ``alignof``
831       alineación de una estructura o tipo.
832
833    Estos son solo los *properties* predefinidos para todos los tipos, pero hay
834    una cantidad considerable de *properties* extra para cada tipo.
835
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
840
841
842
843 .. _d_dbc:
844
845 Programación confiable
846 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
847
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:
852
853 Excepciones:
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.
857
858 ``assert``:
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.
864
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.
868
869    Ejemplo::
870
871       File f = open("archivo");
872       assert (f.ok());
873
874 Diseño por contrato:
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
878    los programas.
879
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 *performance* cuando es necesario):
883
884    Pre y post condiciones:
885       Ejemplo::
886
887          double raiz_cuadrada(double x)
888          in { // pre-condiciones
889             assert (x >= 0.0);
890          }
891          out (resultado) { // post-condiciones
892             assert (resultado >= 0.0);
893             if (x < 1.0)
894                assert (resultado < x);
895             else if (x > 1.0)
896                assert (resultado > x);
897             else
898                assert (resultado == 1);
899          }
900          body {
901             // implementación
902          }
903
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
909       ``assert``.
910
911       Ejemplo::
912
913          class Fecha {
914                int dia;
915                int hora;
916                invariant() {
917                   assert(1 <= dia && dia <= 31);
918                   assert(0 <= hora && hora < 24);
919                }
920          }
921
922    Más información en http://www.digitalmars.com/d/1.0/dbc.html
923
924 Pruebas unitarias:
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()``.
928
929    Ejemplo::
930
931       unittest {
932          Fecha fecha;
933          fecha.dia = 5;
934          assert (fecha.dia == 5);
935          assert (fecha);
936       }
937
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
945    los módulos.
946
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.
953
954    Ejemplo::
955
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)
961
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.
967
968    Esta técnica es la base para desarrollar código seguro en cuanto
969    a excepciones (*exception-safe*) [SUTT99]_.
970
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.
976
977    Ejemplo::
978
979       class Archivo {
980          this() { /* adquiere recurso */ }
981          ~this() { /* libera recurso */ }
982       }
983       void f() {
984          scope Archivo archivo = new Archivo;
985          // uso de archivo
986       } // en este punto se llama al destructor de archivo
987
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.
992
993    Ejemplo::
994
995       int f(Lock lock) {
996          lock.lock();
997          scope (exit)
998             lock.unlock();                  // ejecutado siempre que salga de f()
999          auto trans = new Transaccion;
1000          scope (success)
1001             trans.commit();                // ejecutado si sale con "return"
1002          scope (failure)
1003             trans.rollback();             // ejecutado si sale por una excepción
1004          if (condicion)
1005             throw Exception("error"); // ejecuta lock.unlock() y trans.rollback()
1006          else if (otra_condicion)
1007             return 5;                         // ejecuta lock.unlock() y trans.commit()
1008          return 0;                            // ejecuta lock.unlock() y trans.commit()
1009       }
1010
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*.
1014
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::
1023
1024       class Foo {
1025          synchronized void bar() { /* cuerpo */ }
1026       }
1027
1028    Es equivalente a::
1029
1030       class Foo {
1031          void bar() {
1032             synchronized (this) { /* cuerpo */ }
1033          }
1034       }
1035
1036
1037 Compiladores
1038 ----------------------------------------------------------------------------
1039
1040 Hay, hasta el momento, 3 compiladores de D_ de buena calidad: DMD_, GDC_
1041 y LDC_.
1042
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]_
1047 diferentes.
1048
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
1052    máquina.
1053
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
1056    máquina.
1057
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.
1063
1064 __ http://www.digitalmars.com/d/1.0/changelog.html#new1_041
1065
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.
1071
1072 LDC_ es lo opuesto; un compilador joven, nacido a mediados de 2007 (aunque vio
1073 la luz un año después aproximadamente), su primer *release* fue a principios
1074 de 2009 y tuvo un crecimiento excepcional. En la actualidad inclusive pasa más
1075 pruebas de estrés que el compilador de referencia DMD_.  Como *back-end*
1076 utiliza LLVM_, otro proyecto joven y con una tasa de crecimiento muy alta.
1077
1078 Además de estos compiladores hay varios otros experimentales, pero ninguno de
1079 ellos de calidad suficiente todavía. Por ejemplo hay un compilador
1080 experimental que emite *CIL* (*Common Intermediate Language*), el *bytecode*
1081 de `.NET`_, llamado DNet_. También hay un *fron-end* escrito en D_, llamado
1082 Dil_
1083
1084 Originalmente, dado que GDC_ estaba siendo mantenido y que LDC_ no existía,
1085 este trabajo iba a ser realizado utilizando GDC_ como compilador, dado que al
1086 ser `Software Libre`_ podía ser modificado de ser necesario. Finalmente,
1087 gracias a la excepcional tasa de crecimiento de LDC_ y al abandono de GDC_ se
1088 terminó desarrollando el trabajo utilizando LDC_.
1089
1090
1091
1092 .. include:: links.rst
1093
1094 .. vim: set ts=3 sts=3 sw=3 et tw=78 :