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