puede verse como similar a la directiva del preprocesador de C/C++ ``#if``,
pero a diferencia de esto, en D_ el ``static if`` tiene acceso a todos los
símbolos del compilador (constantes, tipos, variables, etc).
puede verse como similar a la directiva del preprocesador de C/C++ ``#if``,
pero a diferencia de esto, en D_ el ``static if`` tiene acceso a todos los
símbolos del compilador (constantes, tipos, variables, etc).
si no se especifica un tipo al declarar una variable, se infiere del tipo
de su valor de inicialización.
si no se especifica un tipo al declarar una variable, se infiere del tipo
de su valor de inicialización.
cualquier tipo de colección (arreglos estáticos y dinámicos, arreglos
asociativos, clases, estructuras o delegados) puede ser iterada mediante la
sentencia ``foreach``.
cualquier tipo de colección (arreglos estáticos y dinámicos, arreglos
asociativos, clases, estructuras o delegados) puede ser iterada mediante la
sentencia ``foreach``.
clases y funciones pueden ser generalizadas. Esto permite desarrollar
algoritmos genéricos sin importar el tipo de los datos de entrada, siempre
y cuando todos los tipos tengan una *interfaz* común. Esto también es
clases y funciones pueden ser generalizadas. Esto permite desarrollar
algoritmos genéricos sin importar el tipo de los datos de entrada, siempre
y cuando todos los tipos tengan una *interfaz* común. Esto también es
auto i = sumar(5, 6); // i == 11
auto f = sumar(5.0f, 6.0f); // f == 11.0f
auto i = sumar(5, 6); // i == 11
auto f = sumar(5.0f, 6.0f); // f == 11.0f
la especialización de *templates* consiste, al igual que en C++, en proveer
una implementación especializada para un tipo de dato (o valor) de los
parámetros. Especialización parcial se refiere a la capacidad de
la especialización de *templates* consiste, al igual que en C++, en proveer
una implementación especializada para un tipo de dato (o valor) de los
parámetros. Especialización parcial se refiere a la capacidad de
float v = 5.0f, w = 6.0f;
auto f = sumar(&v, &w); // f == 11.0f
float v = 5.0f, w = 6.0f;
auto f = sumar(&v, &w); // f == 11.0f
esto es otro bloque de construcción importantísimo para la programación
genérica en D, ya que combinando *templates* que toman *strings* como
parámetro en combinación con *string mixins* pueden hacerse toda clase de
esto es otro bloque de construcción importantísimo para la programación
genérica en D, ya que combinando *templates* que toman *strings* como
parámetro en combinación con *string mixins* pueden hacerse toda clase de
Esto permite implementar tuplas u otros algoritmos que inherentemente deben
tomar una cantidad variable de parámetros en tiempo de compilación.
Esto permite implementar tuplas u otros algoritmos que inherentemente deben
tomar una cantidad variable de parámetros en tiempo de compilación.
}
double d = sumar(1, 2.0, 3.0f, 4l); // d == 10.0
}
double d = sumar(1, 2.0, 3.0f, 4l); // d == 10.0
si una función cumple ciertas reglas básicas (como por ejemplo no tener
efectos colaterales) puede ser ejecutada en tiempo de compilación en vez de
tiempo de ejecución. Esto permite hacer algunos cálculos que no cambian de
si una función cumple ciertas reglas básicas (como por ejemplo no tener
efectos colaterales) puede ser ejecutada en tiempo de compilación en vez de
tiempo de ejecución. Esto permite hacer algunos cálculos que no cambian de
la palabra *mixin* tiene significados distintos en varios lenguajes de
programación. En D_ *mixin* significa tomar una secuencia arbitraria de
declaraciones e insertarla en el contexto (*scope*) actual. Esto puede
la palabra *mixin* tiene significados distintos en varios lenguajes de
programación. En D_ *mixin* significa tomar una secuencia arbitraria de
declaraciones e insertarla en el contexto (*scope*) actual. Esto puede
las *expresiones ``is``* permiten la compilación condicional basada en las
características de un tipo. Esto se realiza en favor a una técnica
utilizada en C++ de realizar *pattern matching* sobre los parámetros de las
las *expresiones ``is``* permiten la compilación condicional basada en las
características de un tipo. Esto se realiza en favor a una técnica
utilizada en C++ de realizar *pattern matching* sobre los parámetros de las
no es interpretado ni necesita una máquina virtual como otros lenguajes de
más alto nivel como Java_, `C#`_, Python_, etc.
no es interpretado ni necesita una máquina virtual como otros lenguajes de
más alto nivel como Java_, `C#`_, Python_, etc.
por lo tanto, acceso directo al *hardware* y la posibilidad de utilizar
cualquier característica de éste que no esté disponible en el lenguaje.
por lo tanto, acceso directo al *hardware* y la posibilidad de utilizar
cualquier característica de éste que no esté disponible en el lenguaje.
compiladores incluso cuando se utiliza *assembly* (mientras que no se
cambie de arquitectura, por supuesto).
compiladores incluso cuando se utiliza *assembly* (mientras que no se
cambie de arquitectura, por supuesto).
soporta todos los tipos de C y es ABI [#abi]_ compatible con éste. Esto
permite enlazar archivos objeto estándar de C y D_ en un mismo programa.
Además permite interoperar con C a través de ``extern (C)``.
soporta todos los tipos de C y es ABI [#abi]_ compatible con éste. Esto
permite enlazar archivos objeto estándar de C y D_ en un mismo programa.
Además permite interoperar con C a través de ``extern (C)``.
extern (C) printf(const char* format, ...);
printf("3 + 5 == %d\n", 3 + 5); // llama al printf de C
extern (C) printf(const char* format, ...);
printf("3 + 5 == %d\n", 3 + 5); // llama al printf de C
permite asignar estructuras en el *stack* o en el *heap*, haciendo uso de
los servicios del sistema operativo o la biblioteca estándar de C.
permite asignar estructuras en el *stack* o en el *heap*, haciendo uso de
los servicios del sistema operativo o la biblioteca estándar de C.
por objetos *livianos* se entiende no-polimórficos. Es decir, un
agrupamiento de variables análogo al ``struct`` de C, sin tabla virtual ni
otro tipo de *overhead*. Los arreglos *livianos* son arreglos estáticos
por objetos *livianos* se entiende no-polimórficos. Es decir, un
agrupamiento de variables análogo al ``struct`` de C, sin tabla virtual ni
otro tipo de *overhead*. Los arreglos *livianos* son arreglos estáticos
la :ref:`d_generic` permite realizar muchas optimizaciones ya que se
resuelve en tiempo de compilación y por lo tanto aumenta el rendimiento en
la ejecución.
la :ref:`d_generic` permite realizar muchas optimizaciones ya que se
resuelve en tiempo de compilación y por lo tanto aumenta el rendimiento en
la ejecución.
productividad de los programadores. D_ adopta herramientas de muchos lenguajes
de alto nivel, como Java_ y Python_, por ejemplo:
productividad de los programadores. D_ adopta herramientas de muchos lenguajes
de alto nivel, como Java_ y Python_, por ejemplo:
al igual que C/C++ y prácticamente cualquier lenguaje imperativo maneja
automáticamente el *stack*, pero a diferencia de la mayoría de los
lenguajes de bajo nivel, D_ permite manejar el *heap* de manera automática
también a través de un *recolector de basura*.
al igual que C/C++ y prácticamente cualquier lenguaje imperativo maneja
automáticamente el *stack*, pero a diferencia de la mayoría de los
lenguajes de bajo nivel, D_ permite manejar el *heap* de manera automática
también a través de un *recolector de basura*.
un módulo es una unidad que agrupa clases, funciones y cualquier otra
construcción de lenguaje. Un paquete es una agrupación de módulos. D_
asocia un módulo a un archivo fuente (y un archivo objeto cuando éste es
un módulo es una unidad que agrupa clases, funciones y cualquier otra
construcción de lenguaje. Un paquete es una agrupación de módulos. D_
asocia un módulo a un archivo fuente (y un archivo objeto cuando éste es
las funciones pueden ser sobrecargadas (funciones con el mismo nombre pero
distinta cantidad o tipo de parámetros), pueden especificarse argumentos de
entrada, salida o entrada/salida, argumentos por omisión o argumentos
las funciones pueden ser sobrecargadas (funciones con el mismo nombre pero
distinta cantidad o tipo de parámetros), pueden especificarse argumentos de
entrada, salida o entrada/salida, argumentos por omisión o argumentos
los arreglos *dinámicos* son arreglos de longitud variable manejados
automáticamente por el lenguaje (análogos al ``std::vector`` de C++).
Soportan concatenación (a través del operador ``~``), rebanado o *slicing*
los arreglos *dinámicos* son arreglos de longitud variable manejados
automáticamente por el lenguaje (análogos al ``std::vector`` de C++).
Soportan concatenación (a través del operador ``~``), rebanado o *slicing*
al igual que los delegados y arreglos dinámicos y asociativos, los
*strings* son ciudadanos de primera clase, teniendo forma literal y siendo
codificados en UTF-8/16/32. Son un caso particular de arreglo dinámico y es
al igual que los delegados y arreglos dinámicos y asociativos, los
*strings* son ciudadanos de primera clase, teniendo forma literal y siendo
codificados en UTF-8/16/32. Son un caso particular de arreglo dinámico y es
el primero define un nuevo tipo basado en otro. A diferencia de C/C++ el
tipo original no puede ser implícitamente convertido al tipo nuevo (excepto
valores literales), pero la conversión es válida en el otro sentido
el primero define un nuevo tipo basado en otro. A diferencia de C/C++ el
tipo original no puede ser implícitamente convertido al tipo nuevo (excepto
valores literales), pero la conversión es válida en el otro sentido
D_ provee un sistema de documentación embebida, análogo a lo que proveen
Java_ o Python_ en menor medida. Hay comentarios especiales del código que
pueden ser utilizados para documentarlo de forma tal que luego el
D_ provee un sistema de documentación embebida, análogo a lo que proveen
Java_ o Python_ en menor medida. Hay comentarios especiales del código que
pueden ser utilizados para documentarlo de forma tal que luego el
D_ soporta números complejos como ciudadanos de primera clase. Soporta
forma literal de números imaginarios y complejos.
D_ soporta números complejos como ciudadanos de primera clase. Soporta
forma literal de números imaginarios y complejos.
herramientas para soportar este paradigma de forma confiable. Entre las
características más salientes se encuentran:
herramientas para soportar este paradigma de forma confiable. Entre las
características más salientes se encuentran:
objetos polimórficos como los de cualquier lenguaje con orientación real
a objetos. Estos objetos poseen una tabla virtual para despacho dinámico,
todos los métodos son virtuales a menos que se indique lo contrario
objetos polimórficos como los de cualquier lenguaje con orientación real
a objetos. Estos objetos poseen una tabla virtual para despacho dinámico,
todos los métodos son virtuales a menos que se indique lo contrario
D_ no soporta herencia múltiple pero sí interfaces. Una interfaz es
básicamente una tabla virtual, una definición de métodos virtuales que debe
proveer una clase. Las interfaces no proveen una implementación de dichos
D_ no soporta herencia múltiple pero sí interfaces. Una interfaz es
básicamente una tabla virtual, una definición de métodos virtuales que debe
proveer una clase. Las interfaces no proveen una implementación de dichos
la sobrecarga de operadores permite que un objeto tenga una sintaxis
similar a un tipo de dato nativo. Esto es muy importante además para la
programación genérica.
la sobrecarga de operadores permite que un objeto tenga una sintaxis
similar a un tipo de dato nativo. Esto es muy importante además para la
programación genérica.
al igual que C (con respecto a ``struct``) y C++, pueden anidarse clases
dentro de clases. D_ sin embargo provee la posibilidad de acceder
a atributos de la instancia exterior desde la anidada.
al igual que C (con respecto a ``struct``) y C++, pueden anidarse clases
dentro de clases. D_ sin embargo provee la posibilidad de acceder
a atributos de la instancia exterior desde la anidada.
en D_ se refiere a funciones miembro que pueden ser tratadas
sintácticamente como campos de esa clase/estructura.
en D_ se refiere a funciones miembro que pueden ser tratadas
sintácticamente como campos de esa clase/estructura.
Además tipos nativos, clases, estructuras y expresiones tienen
*properties* predefinidos, por ejemplo:
Además tipos nativos, clases, estructuras y expresiones tienen
*properties* predefinidos, por ejemplo:
valor de inicialización por omisión (ejemplo: ``float.init`` -> *NaN*
[#dnan]_).
.. [#dnan] Del inglés *Not A Number*, es un valor especial que indica que
estamos ante un valor inválido.
valor de inicialización por omisión (ejemplo: ``float.init`` -> *NaN*
[#dnan]_).
.. [#dnan] Del inglés *Not A Number*, es un valor especial que indica que
estamos ante un valor inválido.
representación textual del tipo *mutilado* [#dmangle]_.
.. [#dmangle] *Name mangling* es el nombre dado comunmente a una técnica
representación textual del tipo *mutilado* [#dmangle]_.
.. [#dmangle] *Name mangling* es el nombre dado comunmente a una técnica
que ciertas fallas puedan existir directamente). D_ presta particular atención
a esto y provee las siguientes herramientas:
que ciertas fallas puedan existir directamente). D_ presta particular atención
a esto y provee las siguientes herramientas:
D_ soporta excepciones de manera similar a Java_: provee ``try``, ``catch``
y ``finally``. Esto permite que los errores difícilmente pasen
silenciosamente sin ser detectados.
D_ soporta excepciones de manera similar a Java_: provee ``try``, ``catch``
y ``finally``. Esto permite que los errores difícilmente pasen
silenciosamente sin ser detectados.
es una condición que debe cumplirse siempre en un programa, como un chequeo
de integridad. Esto es muy utilizado en C/C++, donde ``assert()`` es una
*macro* que solo se compila cuando la *macro* ``NDEBUG`` no está definida.
es una condición que debe cumplirse siempre en un programa, como un chequeo
de integridad. Esto es muy utilizado en C/C++, donde ``assert()`` es una
*macro* que solo se compila cuando la *macro* ``NDEBUG`` no está definida.
el diseño por contrato es un concepto introducido por el lenguaje Eiffel_
a mediados/finales de los '80. Se trata de incorporar en el lenguaje las
herramientas para poder aplicar verificaciones formales a las interfaces de
el diseño por contrato es un concepto introducido por el lenguaje Eiffel_
a mediados/finales de los '80. Se trata de incorporar en el lenguaje las
herramientas para poder aplicar verificaciones formales a las interfaces de
ejecutan siempre y cuando no se compile en modo *release*, de manera de no
sacrificar rendimiento cuando es necesario):
ejecutan siempre y cuando no se compile en modo *release*, de manera de no
sacrificar rendimiento cuando es necesario):
La invariante de representación es un método de una clase o estructura
que es verificada cuando se completa su construcción, antes de la
destrucción, antes y después de ejecutar cualquier función miembro
La invariante de representación es un método de una clase o estructura
que es verificada cuando se completa su construcción, antes de la
destrucción, antes y después de ejecutar cualquier función miembro
es posible incluir pequeñas pruebas unitarias en el lenguaje. Éstas son
ejecutadas (cuando no se compila en modo *release*) al comenzar el
programa, antes de que la función ``main()``.
es posible incluir pequeñas pruebas unitarias en el lenguaje. Éstas son
ejecutadas (cuando no se compila en modo *release*) al comenzar el
programa, antes de que la función ``main()``.
a diferencia de C++, D_ garantiza el orden de inicialización de los
módulos. Si bien en C++ no hay módulos si no unidades de compilación, es
posible que se ejecute código antes del ``main()`` en C++, si hay, por
a diferencia de C++, D_ garantiza el orden de inicialización de los
módulos. Si bien en C++ no hay módulos si no unidades de compilación, es
posible que se ejecute código antes del ``main()`` en C++, si hay, por
todas las variables son inicializadas por el lenguaje (a menos que el
usuario pida explícitamente que no lo sean). Siempre que sea posible se
elijen valores de inicialización que permitan saber al programador que la
todas las variables son inicializadas por el lenguaje (a menos que el
usuario pida explícitamente que no lo sean). Siempre que sea posible se
elijen valores de inicialización que permitan saber al programador que la
es una técnica muy utilizada en C++ que consiste en reservar recursos por
medio de la construcción de un objeto y liberarlos cuando se libera éste.
Al llamarse al destructor de manera automática cuando se sale del *scope*,
es una técnica muy utilizada en C++ que consiste en reservar recursos por
medio de la construcción de un objeto y liberarlos cuando se libera éste.
Al llamarse al destructor de manera automática cuando se sale del *scope*,
además de poder limitar la vida de una instancia a un *scope*, es posible
especificar un bloque de código arbitrario a ejecutar al abandonar un
*scope*, ya sea cuando se sale del *scope* normalmente o por una falla.
además de poder limitar la vida de una instancia a un *scope*, es posible
especificar un bloque de código arbitrario a ejecutar al abandonar un
*scope*, ya sea cuando se sale del *scope* normalmente o por una falla.
el programador debe tener un poco más de cuidado de especificar las
acciones a ejecutar al finalizar el *scope*.
el programador debe tener un poco más de cuidado de especificar las
acciones a ejecutar al finalizar el *scope*.
la programación multi-hilo está directamente soportada por el lenguaje,
y se provee una primitiva de sincronización al igual que Java_. La palabra
reservada ``synchronized`` puede aparecer como modificador de métodos (en
la programación multi-hilo está directamente soportada por el lenguaje,
y se provee una primitiva de sincronización al igual que Java_. La palabra
reservada ``synchronized`` puede aparecer como modificador de métodos (en