]> git.llucax.com Git - z.facultad/75.00/informe.git/blob - source/d.rst
Corregir cantidad de capítulos
[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, CORREGIDO (A)
6
7
8 .. highlight:: d
9
10 .. _d_lang:
11
12 El lenguaje de programación D
13 ============================================================================
14
15
16 Historia
17 ----------------------------------------------------------------------------
18
19 D_ es un lenguaje de programación relativamente joven. Nació en 1999 y el
20 2 de enero de 2007 salió su `versión 1.0`__. Poco tiempo después se continúo
21 el desarrollo del lenguaje en la `versión 2.0`__, que pasó a ser considerada
22 estable aproximadamente en junio de 2010 con el lanzamiento del libro "The
23 D Programming Language" [ALX10]_, pero aún es un trabajo en progreso.
24
25 __ `D 1.0`_
26 __ `D 2.0`_
27
28 El lenguaje fue diseñado e implementado por `Walter Bright`_, desarrollador
29 principal de Zortech C++, uno de los primeros compiladores de C++ que
30 compilaba a código nativo, y está fuertemente influenciado por éste. Sin
31 embargo toma muchos conceptos de otros lenguajes de más alto nivel, como Java_
32 o incluso lenguajes dinámicos como Perl_, Python_ y Ruby_.
33
34 El origen del lenguaje está plasmado en su sitio web, en donde se cita:
35
36    It seems to me that most of the "new" programming languages fall into one
37    of two categories: Those from academia with radical new paradigms and those
38    from large corporations with a focus on RAD and the web. Maybe it's time
39    for a new language born out of practical experience implementing compilers.
40
41 Esto podría traducirse como:
42
43    Parece que la mayoría de los lenguajes de programación "nuevos" caen en
44    2 categorías: aquellos académicos con nuevos paradigmas radicales
45    y aquellos de grandes corporaciones con el foco en el desarrollo rápido
46    y web. Tal vez es hora de que nazca un nuevo lenguaje de la experiencia
47    práctica implementando compiladores.
48
49 La versión 1.0 fue más bien una etiqueta arbitraria que un indicador real de
50 estabilidad y completitud. Luego de liberarse se siguieron agregando nuevas
51 características al lenguaje hasta que se empezó el desarrollo en paralelo de
52 la versión 2.0 al introducirse el concepto de inmutabilidad y funciones
53 *puras* [#dpure]_ (a mediados de 2007).
54
55 .. [#dpure] Por funciones *puras* en D_ se entiende que no tienen efectos
56    colaterales. Es decir, una función pura siempre que se llame con la misma
57    entrada producirá el mismo resultado. Esto es análogo a como funcionan los
58    lenguajes funcionales en general, abriendo la puerta a la programación de
59    estilo funcional en D_.
60
61 A partir de este momento la versión 1.0 quedó *teóricamente* congelada,
62 introduciendo solo cambios que arreglen errores (*bug fixes*), agregando
63 nuevas características solamente en la versión 2.0 del lenguaje. La realidad
64 es que se hicieron cambios incompatibles a la versión 1.0 del lenguaje en
65 reiteradas ocasiones, pero se fue tendiendo a cada vez introducir menos
66 cambios incompatibles. Sin embargo al día de hoy el compilador de referencia
67 sigue teniendo algunas características presentes en la especificación del
68 lenguaje sin implementar, por lo que todavía no hay una implementación
69 completa de la versión 1.0 del lenguaje.
70
71 El lenguaje ha sido, hasta el desarrollo de la versión 2.0 al menos, un
72 esfuerzo unipersonal de `Walter Bright`_, dados sus problemas a la hora de
73 delegar o aceptar contribuciones. Esto motivó a la comunidad de usuarios de D_
74 a crear bibliotecas base alternativas a la estándar (llamada Phobos_) en las
75 cuales se pudiera trabajar sin las trabas impuestas por el autor del lenguaje.
76
77 En este contexto nacen primero Mango_ y luego Ares_. Mango_ fue creada por
78 Kris Macleod Bell a principios de 2004 como una biblioteca que provee
79 servicios básicos de entrada/salida (o *I/O* de *input/output* en inglés) de
80 alto rendimiento.   Siendo estos servicios algo básico lo más natural hubiera
81 sido que se encuentren en la biblioteca estándar de D_ pero por las
82 dificultades para contribuir a ésta, se desarrolla como una biblioteca
83 separada.   A mediados de 2004 Sean Kelly crea Ares_ , con las mismas
84 motivaciones pero con la intención de crear una biblioteca base (conocida en
85 inglés como *runtime*) que incluye los servicios básicos que necesita el
86 lenguaje (información de tipos, manejo de excepciones e hilos, creación
87 y manipulación de objetos, recolector de basura, etc.). Al poco tiempo de
88 liberarse Ares_, Mango_ empieza a utilizarla como biblioteca base.
89
90 Para comienzos de 2006, se empieza a trabajar en la combinación de ambas
91 bibliotecas para lograr una biblioteca estándar alternativa con un alto grado
92 de cohesión. Finalmente a principios de 2007, coincidiendo por casualidad con
93 la aparición de `D 1.0`_, se anuncia el resultado de este combinación bajo el
94 nombre de Tango_, proveyendo una alternativa completa y madura a la biblioteca
95 estándar de D_ Phobos_.  A principios de 2008 los principales desarrolladores
96 de Tango_ (Kris Bell, Sean Kelly, Lars Ivar Igesund y Michael Parker) publican
97 el libro llamado `Learn to Tango with D`_ [BKIP08]_.
98
99 Esto por un lado fue un gran avance porque dio un impulso muy considerable al
100 lenguaje pero por otro un gran retroceso, porque todavía al día de hoy `D
101 1.0`_ tiene dos bibliotecas base, una estándar pero de peor calidad, menos
102 mantenida y usada; y una alternativa de mayor calidad y apertura a la
103 comunidad (pero no estándar). El peor problema es que ambas son
104 **incompatibles**, por lo que un programa hecho con Tango_ no funciona con
105 Phobos_ y viceversa (a menos que el programador haya invertido una cantidad de
106 tiempo considerable en asegurarse de que funcione con ambas).
107
108 Esto hace que la compatibilidad de programas y bibliotecas esté muy
109 fragmentada entre las dos bibliotecas base. Si bien no parece que vaya a haber
110 solución alguna a este problema para `D 1.0`_, `D 2.0`_ va en camino
111 a solucionar este problema ya que utiliza DRuntime_, un nuevo intento de Sean
112 Kelly por proveer una biblioteca *runtime* bien organizada y mantenida, que es
113 una adaptación de la biblioteca *runtime* de Tango_ a `D 2.0`_. Sin embargo
114 Tango_ no fue adaptada a `D 2.0`_ todavía, y no hay muchas perspectivas de que
115 sea portada en algún momento, por un lado porque en general la comunidad sigue
116 fragmentada entre muchos usuarios de `D 1.0`_ que no están contentos con los
117 cambios introducidos en `D 2.0`_, en su mayoría usuarios de Tango_, y que no
118 planean migrar a esa versión; y por otro porque el desarrollo de Phobos_ 2.0
119 se ha abierto mucho y tiene muchos colaboradores, por lo tanto la mayor parte
120 de la gente que utiliza `D 2.0`_ está contenta con el estado de Phobos_ 2.0.
121
122
123 Descripción general
124 ----------------------------------------------------------------------------
125
126 D_ es un lenguaje de programación con sintaxis tipo C, multi-paradigma,
127 compilado, con *tipado* fuerte y estático, buenas capacidades tanto de
128 programación de bajo nivel (*system programming*) como de alto nivel; además
129 es compatible de forma binaria con C (se puede enlazar código objeto C con
130 código objeto D). Con estas características, D_ logra llenar un vacío
131 importante que hay entre lo lenguajes de alto bajo nivel y los de alto nivel
132 [BKIP08]_. Si bien tiene herramientas de muy bajo nivel, que por lo tanto son
133 muy propensas a errores, da una infinidad de mecanismos para evitar el uso de
134 estas herramientas a menos que sea realmente necesario.  Además pone mucho
135 énfasis en la programación confiable, para lo cual provee muchos mecanismos
136 para detectar errores en los programas de forma temprana.
137
138 Si puede pensarse en C++ como un "mejor C", podría decirse que D_ es un "mejor
139 C++", ya que el objetivo del lenguaje es muy similar a C++, pero implementa
140 muchas características que jamás pudieron entrar en el estándar de C++ y lo
141 hace de una forma mucho más limpia, ya que no debe lidiar con problemas de
142 compatibilidad hacia atrás, y cuenta con la experiencia del camino recorrido
143 por C++, pudiendo extraer de él los mejores conceptos pero evitando sus
144 mayores problemas.
145
146 Otra gran diferencia con C++ es la facilidad para ser analizado
147 sintácticamente (*parsing*), ya que fue especialmente diseñado para ser
148 sencillo y a diferencia de C y C++ su gramática es independiente del contexto
149 (*context-free grammar*). Esto permite que D pueda ser compilado en pequeños
150 pasos bien separados:
151
152 1. Análisis léxico.
153 2. Análisis sintáctico.
154 3. Análisis semántico.
155 4. Optimizaciones.
156 5. Generación de código.
157
158 Esto favorece la creación de herramientas dada la facilidad de usar solamente
159 la cantidad de análisis necesario para cada una (por ejemplo un editor de
160 textos puede tener hasta análisis sintáctico para proveer resaltado o un
161 entorno de desarrollo puede proveer herramientas para re-factorizar el código
162 haciendo uso del análisis semántico).
163
164 Una de las características que nunca pudo entrar en el estándar de C++ es la
165 recolección de basura. D_ no comete el mismo error.
166
167
168 Características del lenguaje
169 ----------------------------------------------------------------------------
170
171 A continuación se enumeran las principales características de D_, agrupadas
172 por unidades funcionales o paradigmas que soporta:
173
174
175
176 .. _d_generic:
177
178 Programación genérica y meta-programación
179 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
180
181 La programación genérica se trata de la capacidad de poder desarrollar
182 algoritmos y estructuras independientes de los tipos que manipulan (pero de
183 forma segura o *type-safe*). Esto fue muy popularizado por C++ gracias a su
184 soporte de plantillas (*templates*) y luego otros lenguajes como Java_ y `C#`_
185 lo siguieron. Sin embargo otros lenguajes proveen formas más avanzadas de
186 programación genérica, gracias a sistemas de tipos más complejos (como
187 Haskell_).
188
189 La meta-programación se refiere en general a la capacidad de un lenguaje para
190 permitir generar código dentro del mismo programa de forma automática.  Esto
191 permite evitar duplicación de código y fue también muy popularizado por el
192 soporte de *templates* de C++, aunque muchos otros lenguajes tienen mejor
193 soporte de meta-programación, en especial los lenguajes dinámicos (como
194 Python_).
195
196 D_ provee las siguientes herramientas para realizar programación genérica
197 y meta-programación:
198
199 ``if`` estático (``static if``)
200    puede verse como similar a la directiva del preprocesador de C/C++ ``#if``,
201    pero a diferencia de esto, en D_ el ``static if`` tiene acceso a todos los
202    símbolos del compilador (constantes, tipos, variables, etc).
203
204    Ejemplo::
205
206       static if ((void*).sizeof == 4)
207          pragma(msg, "32 bits");
208
209    Más información en http://www.digitalmars.com/d/1.0/version.html#staticif
210
211 Inferencia de tipos básica implícita y explícita (mediante ``typeof``)
212    si no se especifica un tipo al declarar una variable, se infiere del tipo
213    de su valor de inicialización.
214
215    Ejemplo::
216
217       static i = 5;      // i es int
218       const d = 6.0;    // d es double
219       auto s = "hola"; // s es string (que es un alias de char[])
220
221    Más información en
222    http://www.digitalmars.com/d/1.0/declaration.html#AutoDeclaration
223
224    Mediante el uso de ``typeof`` se puede solicitar el tipo de una expresión
225    arbitraria.
226
227    Ejemplo::
228
229       typeof(5 + 6.0) d; // d es double
230
231    Más información en http://www.digitalmars.com/d/1.0/declaration.html#typeof
232
233 Iteración sobre colecciones (``foreach``)
234    cualquier tipo de colección (arreglos estáticos y dinámicos, arreglos
235    asociativos, clases, estructuras o delegados) puede ser iterada mediante la
236    sentencia ``foreach``.
237
238    Ejemplo::
239
240       int[] a = [ 1, 2, 3 ];
241       int total = 0;
242       foreach (i; a)
243          total += i;
244
245 *Templates*
246    clases y funciones pueden ser generalizadas. Esto permite desarrollar
247    algoritmos genéricos sin importar el tipo de los datos de entrada, siempre
248    y cuando todos los tipos tengan una *interfaz* común.   Esto también es
249    conocido como *polimorfismo en tiempo de compilación*, y es la forma más
250    básica de programación genérica.
251
252    Ejemplo::
253
254       T sumar(T)(T x, T y) { return x + y; }
255       auto i = sumar!(int)(5, 6);    // i == 11
256       auto f = sumar!(float)(5, 6); // j == 11.0f
257
258    Además se pueden definir bloques de declaraciones generalizadas (esto no
259    es posible en C++), permitiendo instanciar dicho bloque con parámetros
260    particulares. Esto sirve como un mecanismo para la reutilización de código,
261    ya que puede incluirse un mismo bloque en distintos lugares (por ejemplo
262    clases). Un bloque generalizado puede verse como una especie de módulo.
263
264    Ejemplo::
265
266       template bloque(T, U) {
267          T x;
268          U foo(T y);
269       }
270
271       bloque!(int, float).x = 5;
272       float f = bloque!(int, float).foo(7);
273
274    La utilidad más prominente de los bloques generalizados se da al
275    acompañarse de *mixins*.
276
277 Instanciación implícita de funciones generalizadas
278    el lenguaje es capaz de deducir los parámetros siempre que no hayan
279    ambigüedades.
280
281    Ejemplo::
282
283       auto i = sumar(5, 6);          // i == 11
284       auto f = sumar(5.0f, 6.0f); // f == 11.0f
285
286 Especialización explícita y parcial de *templates*
287    la especialización de *templates* consiste, al igual que en C++, en proveer
288    una implementación especializada para un tipo de dato (o valor) de los
289    parámetros.   Especialización parcial se refiere a la capacidad de
290    especializar un parámetro a través de un subtipo. Por ejemplo, se puede
291    especializar un *template* para cualquier tipo de puntero, o para cualquier
292    tipo de arreglo dinámico, sin necesidad de especificar el tipo al que
293    apunta dicho puntero o el tipo almacenado por el arreglo.
294
295    Ejemplo de especialización::
296
297       T sumar(T: int)(T x, T y) { return x + y + 1; }
298       auto i = sumar(5, 6);         // i == 12
299       auto f = sumar(5.0f, 6.0f) // f == 11.0f
300
301    Ejemplo de especialización parcial::
302
303       T sumar(T: T*)(T x, T y) { return *x + *y; }
304       int x = 5, y = 6;
305       auto i = sumar(&x, &y); // i == 11
306       float v = 5.0f, w = 6.0f;
307       auto f = sumar(&v, &w); // f == 11.0f
308
309 Tipos, valores (incluyendo *strings*) y *templates* como parámetros
310    esto es otro bloque de construcción importantísimo para la programación
311    genérica en D, ya que combinando *templates* que toman *strings* como
312    parámetro en combinación con *string mixins* pueden hacerse toda clase de
313    meta-programas.
314
315    Ejemplo::
316
317       template hash(string s, uint so_far=0) {
318          static if (s.length == 0)
319             const hash = so_far;
320          else
321             const hash = hash!(s[1 .. length], so_far * 11 + s[0]);
322       }
323       string s = hash!("hola"); // calculado en tiempo de compilación
324
325 Cantidad de parámetros variables para *templates*
326    Esto permite implementar tuplas u otros algoritmos que inherentemente deben
327    tomar una cantidad variable de parámetros en tiempo de compilación.
328
329    Ejemplo::
330
331       double sumar(T...)(T t) {
332          double res = 0.0;
333          foreach (x; t)
334             res += x;
335          return res;
336       }
337       double d = sumar(1, 2.0, 3.0f, 4l); // d == 10.0
338
339 *CTFE* (*compile-time function execution*)
340    si una función cumple ciertas reglas básicas (como por ejemplo no tener
341    efectos colaterales) puede ser ejecutada en tiempo de compilación en vez de
342    tiempo de ejecución. Esto permite hacer algunos cálculos que no cambian de
343    ejecución en ejecución al momento de compilar, mejorando el rendimiento
344    o permitiendo formas avanzadas de meta-programación. Esta característica se
345    vuelve particularmente útil al combinarse con *string mixins*.
346
347    Ejemplo::
348
349       int factorial(int n) {
350          if (n == 1)
351             return 1;
352          else
353             return n * factorial(n - 1);
354       }
355       static int x = factorial(5); // calculado en tiempo de compilación
356       int x = factorial(5); // calculado en tiempo de ejecución
357
358    Esta característica es vital para evitar la duplicación de código.
359
360 *Mixins*, incluyendo *string mixins*
361    la palabra *mixin* tiene significados distintos en varios lenguajes de
362    programación. En D_ *mixin* significa tomar una secuencia arbitraria de
363    declaraciones e insertarla en el contexto (*scope*) actual. Esto puede
364    realizarse a nivel global, en clases, estructuras o funciones. Esto sirve
365    como un mecanismo para evitar duplicación de código que puede ser
366    introducida por la falta de herencia múltiple.
367
368    Ejemplo::
369
370       class A {
371          mixin bloque!(int, float);
372       }
373       A a = new A;
374       a.x = 5;
375       float f = a.foo(a.x);
376
377       class B {
378          mixin bloque!(long, double);
379       }
380       B b = new B;
381       b.x = 5l;
382       double d = a.foo(a.x);
383
384    *String mixin* se refiere a la capacidad de *incrustar* un *string* que
385    contenga un fragmento de código en un programa como si este fragmento
386    hubiera sido escrito en el código fuente directamente por el programador.
387    Esto permite hacer manipulaciones arbitrariamente complejas en combinación
388    con funciones ejecutadas en tiempo de compilación.
389
390    Ejemplo::
391
392       string generar_sumar(string var_x, string var_y) {
393          return "return " ~ var_x ~ " + " ~ var_y ~ ";";
394       }
395
396       int sumar(int a, int b) {
397          mixin(generar_sumar!("a", b"));
398       }
399
400    Más información en http://www.digitalmars.com/d/1.0/mixin.html
401
402 Expresiones ``is``
403    las *expresiones ``is``* permiten la compilación condicional basada en las
404    características de un tipo.
405
406    Ejemplo::
407
408       T foo(T)(T x) {
409          static if (is(T == class))
410             return new T;
411          else
412             return T.init;
413       }
414
415    Esto provee además una forma simple de reflexión en tiempo de compilación.
416
417    Más información en
418    http://www.digitalmars.com/d/1.0/expression.html#IsExpression
419
420
421
422 .. _d_low_level:
423
424 Programación de bajo nivel (*system programming*)
425 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
426
427 Por programación de bajo nivel nos referimos a la capacidad de un lenguaje de
428 manipular el hardware directamente, o al menos la memoria. C es probablemente
429 el lenguaje de bajo nivel más popular, seguido por C++.
430
431 D_ presenta muchas características de bajo nivel:
432
433 Compila a código de máquina nativo
434    no es interpretado ni necesita una máquina virtual como otros lenguajes de
435    más alto nivel como Java_, `C#`_, Python_, etc.
436
437 Provee acceso a *assembly*
438    por lo tanto, acceso directo al *hardware* y la posibilidad de utilizar
439    cualquier característica de éste que no esté disponible en el lenguaje.
440
441    Una ventaja sobre C y C++ es que el lenguaje *assembly* utilizado dentro de
442    D_ está especificado, por lo que se puede mantener la portabilidad entre
443    compiladores incluso cuando se utiliza *assembly* (mientras que no se
444    cambie de arquitectura, por supuesto).
445
446 ``goto``
447    al igual que C y C++, D_ provee la flexibilidad del uso de ``goto``.
448
449 Compatibilidad con C
450    soporta todos los tipos de C y es ABI [#abi]_ compatible con éste. Esto
451    permite enlazar archivos objeto estándar de C y D_ en un mismo programa.
452    Además permite interoperar con C a través de ``extern (C)``.
453
454    .. [#abi] Interfaz de Aplicación Binaria (del inglés *Application Binary
455       Interface*).
456
457    Ejemplo::
458
459       extern (C) printf(const char* format, ...);
460       printf("3 + 5 == %d\n", 3 + 5); // llama al printf de C
461
462 Manejo de memoria explícito
463    permite asignar estructuras en el *stack* o en el *heap*, haciendo uso de
464    los servicios del sistema operativo o la biblioteca estándar de C.
465
466 Objetos y arreglos *livianos*
467    por objetos *livianos* se entiende no-polimórficos. Es decir, un
468    agrupamiento de variables análogo al ``struct`` de C, sin tabla virtual ni
469    otro tipo de *overhead*. Los arreglos *livianos* son arreglos estáticos
470    como en C, cuyo tamaño es fijo, también sin ningún tipo de *overhead* como
471    C. Además puede asignarse un arreglo dinámicamente usando ``malloc()``
472    y utilizar el operador ``[]`` para accederlo.
473
474    Esto también permite interoperar con C, ya que pueden definirse ``structs``
475    y arreglos que pueden ser intercambiados con dicho lenguaje sin problemas.
476
477    Ejemplo::
478
479       struct timeval {
480          time_t         tv_sec;
481          suseconds_t tv_usec;
482       }
483       extern (C) {
484          void* malloc(size_t);
485          size_t strlen(const char *);
486          int gettimeofday(timeval *, void *);
487       }
488       char* s = cast(char*) malloc(2);
489       s[0] = 'C';
490       s[1] = '\0';
491       size_t l = strlen(s); // l == 1
492       timeval tv;
493       gettimeofday(&tv, null);
494
495 Rendimiento
496    la :ref:`d_generic` permite realizar muchas optimizaciones ya que se
497    resuelve en tiempo de compilación y por lo tanto aumenta el rendimiento en
498    la ejecución.
499
500 Número de punto flotante de 80 bits
501    El tipo ``real`` de D_ tiene precisión de 80 bits si la plataforma lo
502    soporta (por ejemplo en i386).
503
504 Control de alineación de miembros de una estructura
505    Mediante ``align`` se puede especificar la alineación a tener en una
506    estructura.
507
508    Ejemplo::
509
510       align (1)
511       struct paquete_de_red {
512          char   tipo;
513          short valor;
514       }
515       // paquete_de_red.sizeof == 3
516
517
518
519 .. _d_high_level:
520
521 Programación de alto nivel
522 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
523
524 Programación de alto nivel se refiere a construcciones más avanzadas que una
525 sentencia para iterar; expresiones con una semántica más ricas que proveen de
526 mayor expresividad al programador o le permiten focalizarse de mejora manera
527 en los algoritmos independizándose del *hardware* o de como funciona una
528 computadora. Es exactamente el opuesto a :ref:`d_low_level`.
529
530 En general estas características tienen como efecto secundario una mejora de la
531 productividad de los programadores. D_ adopta herramientas de muchos lenguajes
532 de alto nivel, como Java_ y Python_, por ejemplo:
533
534 Manejo automático de memoria
535    al igual que C/C++ y prácticamente cualquier lenguaje imperativo maneja
536    automáticamente el *stack*, pero a diferencia de la mayoría de los
537    lenguajes de bajo nivel, D_ permite manejar el *heap* de manera automática
538    también a través de un *recolector de basura*.
539
540 Sistema de paquetes y módulos (similar a Java_ o Python_)
541    un módulo es una unidad que agrupa clases, funciones y cualquier otra
542    construcción de lenguaje. Un paquete es una agrupación de módulos. D_
543    asocia un módulo a un archivo fuente (y un archivo objeto cuando éste es
544    compilado) y un paquete a un directorio. A diferencia de C/C++ no necesita
545    de un preprocesador para incluir declaraciones de otros *módulos* (en C/C++
546    no existe el concepto de módulo, solo de unidades de compilación).
547
548    Ejemplo:
549
550    ``a.d``::
551
552       module a;
553       void f() {}
554
555    ``b.d``::
556
557       module b;
558       void f() {}
559
560    ``c.d``::
561
562          module c;
563          import a;
564          import b: f;
565          a.f();
566          b.f();
567          f(); // ejecuta b.f()
568
569 Funciones y delegados
570    las funciones pueden ser sobrecargadas (funciones con el mismo nombre pero
571    distinta cantidad o tipo de parámetros), pueden especificarse argumentos de
572    entrada, salida o entrada/salida, argumentos por omisión o argumentos
573    evaluados de forma perezosa (*lazy*). Además pueden tener una cantidad de
574    argumentos variables pero manteniendo información de tipos (más seguro que
575    C/C++).
576
577    Los *delegados* son punteros a función con un contexto asociado. Este
578    contexto puede ser un objeto (en cuyo caso la función es un método) o un
579    *stack frame* (en cuyo caso la función es una función anidada).
580
581    Además de esto los delegados son ciudadanos de primera clase
582    [#1stclasscity]_, disponiendo de forma literal (delegado anónimo), lo que
583    permite construcciones de alto nivel muy conveniente. Los argumentos
584    evaluados de forma perezosa no son más que un delegado que se ejecuta solo
585    cuando es necesario.
586
587    .. [#1stclasscity] Por ciudadano de primera clase se entiende que se trata
588       de un tipo soportado por completo por el lenguaje, disponiendo de
589       expresiones literales anónimas, pudiendo ser almacenados en variables,
590       estructuras de datos, teniendo una identidad intrínseca, más allá de un
591       nombre dado, etc. En realidad los arreglos asociativos no pueden ser
592       expresados como literales anónimos pero sí tienen una sintaxis especial
593       soportada directamente por el lenguaje.
594
595    Ejemplo::
596
597       bool buscar(T[] arreglo, T item, bool delegate(T x, T y) igual) {
598          foreach (t, arreglo)
599             if (igual(t, item))
600                return true;
601          return false;
602       }
603       struct Persona {
604          string nombre;
605       }
606       Persona[] personas;
607       // llenas personas
608       Persona p;
609       p.nombre = "Carlos";
610       bool encontrado = buscar(personas, p,
611                                        (Persona x, Persona y) {
612                                           return x.nombre == y.nombre;
613                                        }
614                                  );
615
616 Arreglos *dinámicos* y arreglos asociativos
617    los arreglos *dinámicos* son arreglos de longitud variable manejados
618    automáticamente por el lenguaje (análogos al ``std::vector`` de C++).
619    Soportan concatenación (a través del operador ``~``), rebanado o *slicing*
620    (a través del operador ``[x..y]``) y chequeo de límites (*bound checking*).
621
622    Los arreglos asociativos (también conocidos como *hashes* o diccionarios)
623    también son provistos por el lenguaje.
624
625    Ambos son ciudadanos de primera clase, disponiendo de forma literal.
626
627    Ejemplo::
628
629       int[] primos = [ 2, 3, 5, 7, 11, 13, 17, 19 ];
630       primos ~= [ 23, 29 ];
631       auto menores_que_10 = primos[0..4]; // [ 2, 3, 5, 7 ]
632       int[string] agenda;
633       agenda["Pepe"] = 5555_1234;
634
635 *Strings*
636    al igual que los delegados y arreglos dinámicos y asociativos, los
637    *strings* son ciudadanos de primera clase, teniendo forma literal y siendo
638    codificados en UTF-8/16/32. Son un caso particular de arreglo dinámico y es
639    posible utilizarlos en sentencias ``switch``/``case``.
640
641    Ejemplo::
642
643       string s = "árbol";
644
645       switch (s) {
646          case "árbol":
647             s = "tree";
648          default:
649             s = "";
650       }
651
652 ``typedef`` y ``alias``
653    el primero define un nuevo tipo basado en otro. A diferencia de C/C++ el
654    tipo original no puede ser implícitamente convertido al tipo nuevo (excepto
655    valores literales), pero la conversión es válida en el otro sentido
656    (similar a los ``enum`` en C++). Por el contrario, ``alias`` es análogo al
657    ``typedef`` de C/C++ y simplemente es una forma de referirse al mismo tipo
658    con un nombre distinto.
659
660    Ejemplo::
661
662       typedef int tipo;
663       int foo(tipo x) {}
664       tipo t = 10;
665       int i = 10;
666       foo(t);
667       foo(i); // error, no compila
668       alias tipo un_alias;
669       un_alias a = t;
670       foo(a);
671
672 Documentación embebida
673    D_ provee un sistema de documentación embebida, análogo a lo que proveen
674    Java_ o Python_ en menor medida. Hay comentarios especiales del código que
675    pueden ser utilizados para documentarlo de forma tal que luego el
676    compilador pueda extraer esa información para generar un documento.
677
678    Más información en http://www.digitalmars.com/d/1.0/ddoc.html
679
680 Números complejos
681    D_ soporta números complejos como ciudadanos de primera clase. Soporta
682    forma literal de números imaginarios y complejos.
683
684    Ejemplo::
685
686       ifloat im = 5.0i;
687       float   re = 1.0;
688       cfloat c   = re + im; // c == 1.0 + 5.0i
689
690
691
692 Programación orientada a objetos
693 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
694
695 La orientación a objetos es probablemente el paradigma más utilizado en la
696 actualidad a la hora de diseñar e implementar un programa. D_ provee muchas
697 herramientas para soportar este paradigma de forma confiable. Entre las
698 características más salientes se encuentran:
699
700 Objetos *pesados*
701    objetos polimórficos como los de cualquier lenguaje con orientación real
702    a objetos. Estos objetos poseen una tabla virtual para despacho dinámico,
703    todos los métodos son virtuales a menos que se indique lo contrario
704    y tienen semántica de referencia [#drefsem]_. Estos objetos tienen un
705    *overhead* comparados a los objetos *livianos* pero aseguran una semántica
706    segura para trabajar con orientación a objetos, evitando problemas con los
707    que se enfrenta C++ (como *slicing* [#dslicing]_) debido a que permite
708    semántica por valor [#dvalsem]_.
709
710    .. [#drefsem] Semántica de referencia significa que el tipo es tratado como
711       si fuera un puntero. Nunca se hacen copias del objeto, siempre se pasa
712       por referencia.
713    .. [#dslicing] Este problema se da en C++ cuando se pasa una clase derivada
714       a una función que acepta una clase base por valor como parámetro. Al
715       realizarse una copia de la clase con el constructor de copia de la clase
716       base, se pierden (o *rebanan*) los atributos de la clase derivada, y la
717       información de tipos en tiempo de ejecución (*RTTI*).
718    .. [#dvalsem] Semántica de valor significa que el tipo es tratado como si
719       fuera un valor concreto. En general se pasa por valor y se hacen copias
720       a menos que se utilice explícitamente un puntero.
721
722    D_ además soporta tipos de retorno covariantes para funciones virtuales.
723    Esto significa que una función sobreescrita por una clase derivada puede
724    retornar un tipo que sea derivado del tipo retornado por la función
725    original sobreescrita.
726
727    Ejemplo::
728
729       class A { }
730       class B : A { }
731
732       class Foo {
733          A test() { return null; }
734       }
735
736       class Bar : Foo {
737          B test() { return null; } // sobreescribe y es covariante con Foo.test()
738       }
739
740    Más información en http://www.digitalmars.com/d/1.0/function.html
741
742 Interfaces
743    D_ no soporta herencia múltiple pero sí interfaces. Una interfaz es
744    básicamente una tabla virtual, una definición de métodos virtuales que debe
745    proveer una clase. Las interfaces no proveen una implementación de dichos
746    métodos, ni pueden tener atributos. Esto simplifica mucho el lenguaje y no
747    se pierde flexibilidad porque puede conseguirse el mismo efecto de tener
748    herencia múltiple a través de interfaces y *mixins* para proveer una
749    implementación o atributos en común a varias clases que implementan la
750    misma interfaz.
751
752 Sobrecarga de operadores
753    la sobrecarga de operadores permite que un objeto tenga una sintaxis
754    similar a un tipo de dato nativo. Esto es muy importante además para la
755    programación genérica.
756
757 Clases anidadas
758    al igual que C (con respecto a ``struct``) y C++, pueden anidarse clases
759    dentro de clases. D_ sin embargo provee la posibilidad de acceder
760    a atributos de la instancia exterior desde la anidada.
761
762    Ejemplo::
763
764       class Exterior {
765          int m;
766          class Anidada {
767             int foo() {
768                return m; // ok, puede acceder a un miembro de Exterior
769             }
770          }
771       }
772
773    Esto tiene un pequeño *overhead* ya que la clase ``Anidada`` debe guardar
774    un puntero a la clase ``Exterior``. Si no se necesita este comportamiento
775    es posible evitar este *overhead* utilizando ``static``, en cuyo caso solo
776    puede acceder a atributos estáticos de la clase ``Exterior``.
777
778    Ejemplo::
779
780       class Exterior {
781          int m;
782          static int n;
783          static class Anidada {
784             int foo() {
785                //return m; // error, miembro de Exterior
786                return n; // ok,   miembro estático de Exterior
787             }
788          }
789       }
790
791
792 Propiedades (*properties*)
793    en D_ se refiere a funciones miembro que pueden ser tratadas
794    sintácticamente como campos de esa clase/estructura.
795
796    Ejemplo::
797
798       class Foo {
799          int data() { return _data; } // propiedad de lectura
800          int data(int value) { return _data = value; } // de escritura
801          private int _data;
802       }
803       Foo f = new Foo;
804       f.data = 1;       // llama a f.data(1)
805       int i = f.data; // llama a f.data()
806
807    Además tipos nativos, clases, estructuras y expresiones tienen
808    *properties* predefinidos, por ejemplo:
809
810    ``sizeof``
811       tamaño ocupado en memoria (ejemplo: ``int.sizeof`` -> 4).
812
813    ``init``
814       valor de inicialización por omisión (ejemplo: ``float.init`` -> *NaN*
815       [#dnan]_).
816
817    .. [#dnan] Del inglés *Not A Number*, es un valor especial que indica que
818       estamos ante un valor inválido.
819
820    ``stringof``
821       representación textual del símbolo o expresión (ejemplo:
822       ``(1+2).stringof`` -> ``"1 + 2"``).
823
824    ``mangleof``
825       representación textual del tipo *mutilado* [#dmangle]_.
826
827    .. [#dmangle] *Name mangling* es el nombre dado comunmente a una técnica
828       necesaria para poder sobrecargar nombres de símbolos. Consiste en
829       codificar los nombres de las funciones tomando como entrada el nombre de
830       la función y la cantidad y tipo de parámetros, asegurando que dos
831       funciones con el mismo nombre pero distintos parámetros (sobrecargada)
832       tengan nombres distintos.
833
834    ``alignof``
835       alineación de una estructura o tipo.
836
837    Estos son solo los *properties* predefinidos para todos los tipos, pero hay
838    una cantidad considerable de *properties* extra para cada tipo.
839
840    Más información sobre *properties* de clases en
841    http://www.digitalmars.com/d/1.0/property.html#classproperties y sobre
842    *properties* predefinidos en
843    http://www.digitalmars.com/d/1.0/property.html
844
845
846
847 .. _d_dbc:
848
849 Programación confiable
850 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
851
852 Programación confiable se refiere a las capacidades o facilidades que provee
853 el lenguaje para evitar fallas de manera temprana (o la capacidad de evitar
854 que ciertas fallas puedan existir directamente). D_ presta particular atención
855 a esto y provee las siguientes herramientas:
856
857 Excepciones
858    D_ soporta excepciones de manera similar a Java_: provee ``try``, ``catch``
859    y ``finally``. Esto permite que los errores difícilmente pasen
860    silenciosamente sin ser detectados.
861
862 ``assert``
863    es una condición que debe cumplirse siempre en un programa, como un chequeo
864    de integridad. Esto es muy utilizado en C/C++, donde ``assert()`` es una
865    *macro* que solo se compila cuando la *macro* ``NDEBUG`` no está definida.
866    Esto permite eliminar los chequeos de integridad del programa, que pueden
867    ser costosos, para versiones que se suponen estables.
868
869    D_ lleva este concepto más allá y hace al ``assert`` parte del lenguaje.
870    Si una verificación no se cumple, lanza una excepción. El ``assert`` no es
871    compilado cuando se utiliza una opción del compilador.
872
873    Ejemplo::
874
875       File f = open("archivo");
876       assert (f.ok());
877
878 Diseño por contrato
879    el diseño por contrato es un concepto introducido por el lenguaje Eiffel_
880    a mediados/finales de los '80. Se trata de incorporar en el lenguaje las
881    herramientas para poder aplicar verificaciones formales a las interfaces de
882    los programas.
883
884    D_ implementa las siguientes formas de diseño por contrato (todas se
885    ejecutan siempre y cuando no se compile en modo *release*, de manera de no
886    sacrificar rendimiento cuando es necesario):
887
888    Pre y post condiciones
889       Ejemplo::
890
891          double raiz_cuadrada(double x)
892          in { // pre-condiciones
893             assert (x >= 0.0);
894          }
895          out (resultado) { // post-condiciones
896             assert (resultado >= 0.0);
897             if (x < 1.0)
898                assert (resultado < x);
899             else if (x > 1.0)
900                assert (resultado > x);
901             else
902                assert (resultado == 1);
903          }
904          body {
905             // implementación
906          }
907
908    Invariantes de representación
909       La invariante de representación es un método de una clase o estructura
910       que es verificada cuando se completa su construcción, antes de la
911       destrucción, antes y después de ejecutar cualquier función miembro
912       pública y cuando se lo requiere de forma explícita utilizando
913       ``assert``.
914
915       Ejemplo::
916
917          class Fecha {
918                int dia;
919                int hora;
920                invariant() {
921                   assert(1 <= dia && dia <= 31);
922                   assert(0 <= hora && hora < 24);
923                }
924          }
925
926    Más información en http://www.digitalmars.com/d/1.0/dbc.html
927
928 Pruebas unitarias
929    es posible incluir pequeñas pruebas unitarias en el lenguaje. Éstas son
930    ejecutadas (cuando no se compila en modo *release*) al comenzar el
931    programa, antes de que la función ``main()``.
932
933    Ejemplo::
934
935       unittest {
936          Fecha fecha;
937          fecha.dia = 5;
938          assert (fecha.dia == 5);
939          assert (fecha);
940       }
941
942 Orden de construcción estática
943    a diferencia de C++, D_ garantiza el orden de inicialización de los
944    módulos. Si bien en C++ no hay módulos si no unidades de compilación, es
945    posible que se ejecute código antes del ``main()`` en C++, si hay, por
946    ejemplo, instancias globales con un constructor definido. C++ no garantiza
947    un orden de inicialización, lo que trae muchos problemas. En D_ se define
948    el orden de inicialización y es el mismo orden en que el usuario importa
949    los módulos.
950
951 Inicialización garantizada
952    todas las variables son inicializadas por el lenguaje (a menos que el
953    usuario pida explícitamente que no lo sean). Siempre que sea posible se
954    elijen valores de inicialización que permitan saber al programador que la
955    variable no fue inicializada explícitamente, de manera de poder detectar
956    errores de manera temprana.
957
958    Ejemplo::
959
960       double d;      // inicializado a NaN
961       int x;         // inicializado a 0
962       Fecha f;       // inicializado a null
963       byte[5] a;     // inicializados todos los valores a 0
964       long l = void; // NO inicializado (explícitamente)
965
966 *RAII* (*Resource Adquisition Is Initialization*)
967    es una técnica muy utilizada en C++ que consiste en reservar recursos por
968    medio de la construcción de un objeto y liberarlos cuando se libera éste.
969    Al llamarse al destructor de manera automática cuando se sale del *scope*,
970    se asegura que el recurso será liberado también.
971
972    Esta técnica es la base para desarrollar código seguro en cuanto
973    a excepciones (*exception-safe*) [SUTT99]_.
974
975    En D_ no es tan común utilizar *RAII* dada la existencia del recolector de
976    basura (en la mayoría de los casos el recurso a administrar es
977    sencillamente memoria). Sin embargo en los casos en donde es necesario,
978    puede utilizarse *RAII* mediante la utilización de la palabra reservada
979    ``scope``, que limita la vida de un objeto un bloque de código.
980
981    Ejemplo::
982
983       class Archivo {
984          this() { /* adquiere recurso */ }
985          ~this() { /* libera recurso */ }
986       }
987       void f() {
988          scope Archivo archivo = new Archivo;
989          // uso de archivo
990       } // en este punto se llama al destructor de archivo
991
992 Guardias de bloque (*scope guards*)
993    además de poder limitar la vida de una instancia a un *scope*, es posible
994    especificar un bloque de código arbitrario a ejecutar al abandonar un
995    *scope*, ya sea cuando se sale del *scope* normalmente o por una falla.
996
997    Ejemplo::
998
999       int f(Lock lock) {
1000          lock.lock();
1001          scope (exit)
1002             lock.unlock();              // ejecutado siempre que salga de f()
1003          auto trans = new Transaccion;
1004          scope (success)
1005             trans.commit();             // ejecutado si sale con "return"
1006          scope (failure)
1007             trans.rollback();           // ejecutado si sale por una excepción
1008          if (condicion)
1009             throw Exception("error");   // lock.unlock() y trans.rollback()
1010          else if (otra_condicion)
1011             return 5;                   // lock.unlock() y trans.commit()
1012          return 0;                      // lock.unlock() y trans.commit()
1013       }
1014
1015    Esta es una nueva forma de poder escribir código *exception-safe*, aunque
1016    el programador debe tener un poco más de cuidado de especificar las
1017    acciones a ejecutar al finalizar el *scope*.
1018
1019 Primitivas de sincronización de hilos
1020    la programación multi-hilo está directamente soportada por el lenguaje,
1021    y se provee una primitiva de sincronización al igual que Java_. La palabra
1022    reservada ``synchronized`` puede aparecer como modificador de métodos (en
1023    cuyo caso se utiliza un *lock* por clase para sincronizar) o como una
1024    sentencia, en cuyo caso se crea un *lock* global por cada bloque
1025    ``synchronized`` a menos que se especifique sobre qué objeto realizar la
1026    sincronización. Por ejemplo::
1027
1028       class Foo {
1029          synchronized void bar() { /* cuerpo */ }
1030       }
1031
1032    Es equivalente a::
1033
1034       class Foo {
1035          void bar() {
1036             synchronized (this) { /* cuerpo */ }
1037          }
1038       }
1039
1040
1041 Compiladores
1042 ----------------------------------------------------------------------------
1043
1044 Hay, hasta el momento, 3 compiladores de D_ de buena calidad: DMD_, GDC_
1045 y LDC_.
1046
1047 DMD_ es el compilador de referencia, escrito por `Walter Bright`_. El
1048 *front-end* [#frontend]_ de este compilador ha sido liberado bajo licencia
1049 Artistic_/GPL_ y es utilizado por los otros dos compiladores, por lo tanto en
1050 realidad hay solo un compilador disponible con 3 *back-ends* [#backend]_
1051 diferentes.
1052
1053 .. [#frontend] *Front-end* es la parte del compilador encargada de hacer el
1054    análisis léxico, sintáctico y semántico del código fuente, generando una
1055    representación intermedia que luego el *back-end* convierte a código de
1056    máquina.
1057
1058 .. [#backend] El *back-end* es la parte del compilador encargada de convertir
1059    la representación intermedia generada por el *front-end* a código de
1060    máquina.
1061
1062 Con `DMD 1.041`__ se publicó el código fuente completo del compilador, pero
1063 con una licencia muy restrictiva para uso personal, por lo que el único efecto
1064 logrado por esto es que la gente pueda mandar parches o correcciones del
1065 compilador pero no lo convierte en `Software Libre`_, siendo el único de los
1066 3 compiladores que no tiene esta característica.
1067
1068 __ http://www.digitalmars.com/d/1.0/changelog.html#new1_041
1069
1070 El compilador GDC_ es el *front-end* de DMD_ utilizando al compilador GCC_
1071 como *back-end*. Fue un muy buen compilador pero estuvo abandonado por casi
1072 tres años. A mediados de este año recibió un nuevo impulso y de a poco se está
1073 poniendo al día con los *front-ends* actuales de DMD_ 1.0 y 2.0, aunque la
1074 versión 2.0 viene bastante más rezagada y todavía no es una alternativa viable
1075 a DMD_.
1076
1077 LDC_ sufrió una suerte similar, es un compilador joven que utiliza como
1078 *back-end* a LLVM_ (una infraestructura modera para construir compiladores),
1079 nacido a mediados de 2007 como un proyecto personal y privado de Tomas
1080 Lindquist Olsen, que estuvo trabajando de forma privada en el proyecto hasta
1081 mediados de 2008, momento en que decide publicar el código mediante una
1082 licencia libre.  Para ese entonces el compilador era todavía inestable
1083 y faltaban implementar varias cosas, pero el estado era lo suficientemente
1084 bueno como para captar varios colaboradores muy capaces, como `Christian
1085 Kamm`_ y Frits Van Bommel que rápidamente se convirtieron en parte fundamental
1086 del proyecto. El primer *release* (0.9) de una versión relativamente completa
1087 y estable fue a principios de 2009 que fue seguido por la versión 0.9.1 que
1088 como puntos más salientes agregó soporte para x86-64 y assembly embebido. El
1089 compilador tuvo un crecimiento excepcional pero estuvo muy inactivo por algún
1090 tiempo y, si bien sigue siendo mantenido, en general los nuevos *front-end* de
1091 DMD_ llevan tiempo de integrar y no está al día con el *back-end* de LLVM_
1092 (por ejemplo desde que se actualizó para utilizar LLVM_ 2.7 que perdió la
1093 capacidad de generar símbolos de depuración).
1094
1095 Además de estos compiladores hay varios otros experimentales, pero ninguno de
1096 ellos de calidad suficiente todavía. Por ejemplo hay un compilador
1097 experimental que emite *CIL* (*Common Intermediate Language*), el *bytecode*
1098 de `.NET`_, llamado DNet_. También hay un *front-end* escrito en D_, llamado
1099 Dil_.
1100
1101 Originalmente, dado que GDC_ estaba siendo mantenido y que LDC_ no existía,
1102 este trabajo iba a ser realizado utilizando GDC_ como compilador, dado que al
1103 ser `Software Libre`_ podía ser modificado de ser necesario. Pero finalmente,
1104 dada la poca confiabilidad que presenta la continuidad del desarrollo de tanto
1105 GDC_ como LDC_, y que el código de DMD_ está disponible en su totalidad
1106 (aunque no sea `Software Libre`_ por completo), se optó por utilizar este
1107 último, dado que es la implementación de referencia que fue más constantemente
1108 mantenida y desarrollada.
1109
1110
1111 .. include:: links.rst
1112
1113 .. vim: set ts=3 sts=3 sw=3 et tw=78 spelllang=es :