Вы находитесь на странице: 1из 32

En este artculo se har una introduccin al lenguaje de programacin D para lo

cual se explicarn las principales diferencias con respecto a C y C++; por ello
sera aconsejable que el lector de este pequeo artculo cono!ca las
caractersticas dichos lenguajes "u otros similares# como $a%a o C&' y algunos
conceptos como la programacin orientada a objetos o el control de errores
mediante excepciones aunque no es necesario que sea un experto en dichos
temas( Este artculo no es un manual ni un tutorial y por lo tanto no es la mejor
referencia para aprender el lenguaje# aunque alguien que cono!ca C++ o de
$a%a podr tener una idea muy completa de D tras leerlo( En mi opinin# D es
un lenguaje con un potencial increible# capa! de proporcionar al desarrollador la
producti%idad y la elegancia de )ython o *uby pero con la eficiencia de C(
Este documento no est terminado y se ir ampliando con el tiempo; puede
%erse una lista de las cuestiones pendientes al final del mismo( +a %ersin
actual es la, -(. actuali!ada el /0 de septiembre de 1--0( El documento es
bsicamente un resumen de la documentacin de D# traducido# y por lo tanto la
mayora de los ejemplos estn tomados de la misma( 2consejo al lector
interesado en el lenguaje que tras leer el artculo y haberse hecho una idea
general# lea la referencia completa en digitalmars(com3d(
Cambios al artculo,
/0 de septiembre, ampliada la seccin de cadenas# creada seccin de
propiedades "diatriba incluida'# creada seccin de guardas de mbito(
2rreglado 4bug4 en el ejemplo de los delegados "gracias 5iguel('
67u8 tipo de lenguaje es D9
+a clasificacin del lenguaje de programacin D sera, lenguaje compilado a
cdigo nati%o "con compilacin opcional a (:E; como C&'# orientado a objetos
pero permitiendo programar con funciones libres y clases ligeras "structs'# con
plantillas y mixins "que permiten la programacin gen8rica' y con posibilidad de
acceso a bajo ni%el(
67u8 diferencias tiene con respecto a C++9
Esta clasificacin parece exactamente la misma que la de C++ y no es casual#
pues C++ es el lenguaje al que D aspira a sustituir( D es un lenguaje
e%olucionario# no re%olucionario y en un principio puede parecer que no aporta
demasiado sobre C++( )ero no son las caractersticas generales sino los
detalles de las mismas los que marcan la diferencia( En primer lugar D conser%a
todas las caractersticas de expresi%idad de C++ "cosa que ni C& ni mucho
menos $a%a consiguen en su afn por hacerse lenguajes ms accesibles'# pero
con una sintaxis y unas construcciones mucho ms sencillas y lgicas( 2dems#
otro de los puntos fuertes de C++# su rendimiento# tambi8n se %e reflejado en
D "en algunas ocasiones incluso superado('
)or otro lado D cuenta con muchas otra caractersticas de las que C++ no
dispone# de las cuales %amos a hacer un pequeo repaso a continuacin(
7uisiera recordar al lector que# al contrario de lo que pasa con $a%a o C&# estas
caractersticas no suponen una perdida apreciable de rendimiento para D en
comparacin con C++,
<estin automtica de memoria "recoleccin de
basura'
En C++ cuando creamos objetos que queremos que transciendan el mbito de
la funcin# m8todo o bloque de cdigo que los ha creado los creamos con
utili!ando el operador 4ne=4( Este operador se encargar de asignar
automticamente la memoria que sea necesaria para el objeto y llamar a su
constructor# de%ol%i8ndonos una referencia al objeto ya iniciali!ado que
podremos almacenar en una %ariable del tipo del objeto(
Cuando ya no %amos a necesitar el objeto procedemos a borrarlo con el
operador 4delete4 lo que liberar la memoria asignada por el objeto( >6)arece
sencillo %erdad9 ?ien# debera serlo# pero en la prctica es raro el programa en
C++ que no tiene o ha tenido una fuga de memoria porque el flujo de ejecucin
de una parte del mismo termina antes de llegar al delete "y por lo tanto la
memoria queda asignada para siempre sin posibilidad de recuperarla' o que ha
fallado porque errneamente se ha hecho un delete del mismo objeto dos %eces
o se ha intentado acceder "tambi8n errneamente' a un miembro de un objeto
pre%iamente borrado( @b%iamente estos errores son e%itables pero errar es
humano y cuantas ms tareas delegue en el programador el lenguaje de
programacin ms posibilidad hay de que haya errores "si no fuera as# todos
seguiramos haciendo ensamblador('
+a gestin automtica de memoria quiere decir que el programador seguir
creando los nue%os objetos con 4ne=4 pero ya no tendr que preocuparse de
borrarlos con 4delete4 porque existir un 4recolector de basura4 que se
encargar de eliminar automticamente los objetos para los que ya no exista
ninguna referencia( Es decir# si tenemos la siguiente funcin,
%oid pierdeaceite"' A
@bj Bo C ne= @bj"';
D
En C++ esto producira una fuga de memoria cada %e! que la llamramos
porque al terminar la funcin ya no habra ninguna referencia a 4o4 "y por lo
tanto no podramos usarlo' y sin embargo al no haber hecho delete seguira
existiendo en la memoria( El cdigo equi%alente en D,
%oid nopierdeaceite"' A
@bj o C ne= @bj"';
D
:o producira ninguna perdida de memoria porque el recolector de basura
detectara que como 4o4 fue declarado dentro de 4nopierdeaceite4 y su alcance
termina al terminar la funcin# la memoria puede ser liberada(
Esta caracterstica "con la que cuentan tambi8n C& y $a%a' puede desacti%arse
si por cuestiones de rendimiento o de cualquier otro tipo no queremos que se
ejecute el recolector de basura llamando a gc(disable"' y luego reacti%arse
llamando a gc(enable"'( +o ms espectacular es que mientras el recolector de
basura sigue desacti%ado las referencias a los objetos que hagamos con 4ne=4
se seguirn contabili!ando por lo que una %e! que reEacti%emos la recoleccin
de basura esos objetos sern igualmente gestionados "no necesitaremos llamar
a delete sobre los mismos(' Esto no es as en C& ni en $a%a#por ejemplo(
Finalmente tambi8n podemos borrar# como en C++# nosotros mismos los
objetos llamando a 4delete4 sin que ello cause ningGn tipo de conflicto con el
recolector de basura(
<estin de errores mediante manejo de
excepciones
C++ permite gestionar los errores mediante el mecanismo de manejo de
excepciones# aunque por herencia de C en demasiadas ocasiones se sigue
utili!ando el sistema de 4%alores mgicos de%ueltos por la funcin4(
En D el sistema de manejo de excepciones es superior al de C++ al incorporar
algunas caractersticas de lenguajes ms recientes( Cuando una excepcin
producida en cdigo D no se captura# se muestra un mensaje de error con
informacin de la excepcin( +a sintxis es parecida a la de otros lenguajes con
manejo de excepciones,
try A
thro= ne= Exception"4mensaje de error4';
D
catch"Exception e' A
printf"4capturada la excepcin# mensaje, H(BsIn4# e(msg';
D finally A
printf"4este mensaje se mostrar siempre4';
D
El cdigo que se ejecuta dentro del ;ry en caso de lan!ar una excepcin se
ejecutar el cdigo que est8 en el bloque del 4catch4 si la excepcin
especificada entre par8ntesis coincide con la lan!ada o es padre de la misma en
la jerarqua de la excepcin "las excepciones son clases con su propia
jerarqua(' El padre de la jerarqua es la clase 4Exception4 as que en ejemplo el
catch capturara cualquier excepcin( En el caso del constructor de la excepcin
en la instruccin que lo lan!a "el 4thro=4' hemos especificado una cadena como
parmetro pues en la clase Exception el argumento del constructor es un
mensaje que queda almacenado en el miembro 4msg4# que generalmente se %a
a usar para amplar la informacin del error# y ese miembro es el que
imprimimos precisamente en el printf del catch(
El bloque con la instruccin 4finally4 se ejecutar siempre# se produ!ca una
excepcin o no y en caso de que se produ!ca incluso aunque se capture en un
catch( )or lo tanto la salida de este programa sera,
capturada la excepcin# mensaje, mensaje de error
este mensaje se mostrar siempre
<uardas de mbito para asegurar la ejecucin de
cdigo a la salida de un mbito
2unque D tenga recoleccin automtica de memoria hay otro tipo de recursos
que se siguen teniendo que liberar manualmente( Ejemplos de estos recursos
son los ficheros# los cerrojos y mutex; pero hay otros( :ormalmente un cdigo
como 8ste "robado de la pgina de D'
%oid mifuncion"' A
5utex cerrojo C ne= 5utex"';
locJ"cerrojo'; 332dquirimos
funcionpeligrosa"'; 33 )uede lan!ar excepciones
unlocJ"cerrojo'; 33 +iberamos
D

En este ejemplo puede %erse fcilmente el problema, si 4funcionpeligrosa4
lan!a una excepcin# no se llama al 4unlocJ"cerrojo'4 y por lo tanto el mutex
queda bloqueado 4para siempre4( Kna posible solucin es usar una construccin
de tipo try((( finally y poner el unlocJ dentro del finally# relan!ando de nue%o la
excepcin recibida# pero D nos ofrece una solucin ms escueta y elegante
llamada 4Lcope <uards4 "4<uardas de Mmbito4(' +os scope guards se
implementan llamando a la palabra cla%e scope poniendo entre par8ntesis el
mbito y despu8s una linea o ms "con lla%es en el segundo caso(' +o que hace
es sencillo, cuando se llegue alcance el mbito especificado# se ejecutar el
cdigo que hubi8ramos asociado con el scope( +o %eremos ms fcilmente con
el ejemplo,
%oid mifuncion"' A
5utex cerrojo C ne= 5utex"';
locJ"cerrojo';
scope"exit' unlocJ"cerrojo';
funcionpeligrosa"';
D

Con este cdigo estamos indicando que cuando salgamos "4exit4' del mbito
"4scope4' actual# se ejecutar unlocJ"'( Ksando exit garanti!amos que el unlocJ
se ejecutar en cualquier caso al salir# sea esta salida de forma normal o por
una excepcin "sin interrumpir el flujo de esta# por lo que no hace falta
relan!arla(' Existen %arios especificadores de mbito para scope# que son,
sucess, Le ejecutar cuando se salga con 8xito "sin excepcin('
failure, Le ejecutar cuando se salga con error "con una excepcin('
exit, Le ejecutar cuando se salga del mbito en cualquier caso
"8xito o error('
*ealmente# usando las guardas de mbito# la instruccin finally nunca es
necesaria aunque se sigue manteniendo en el lenguaje( )or comparacin# la
4antigua4 forma de hacer esto sera,
%oid mifuncion"' A
try A
5utex cerrojo C ne= 5utex"';
locJ"cerrojo';
funcionpeligrosa"';
D finally A
unlocJ"cerrojo';
thro="o';
D

+as guardas de inclusin no sustituyen a la instruccin except; para capturar
excepciones y reali!ar operaciones en la captura debemos seguir usndola(
)ara los )ythoneros# la guarda de mbito de 8xito "sucess' sera equi%alente a
el 4else4 de las excepciones en )ython(
Estructuracin del cdigo en mdulos y paquetes
En C3C++ la estructuracin del cdigo se hace creando 4ficheros de cabecera4
con extensin (h o (hpp que contienen las declaraciones de los smbolos que
cada subparte explorta# y luego esos ficheros de cabecera se importan usando
la directi%a del preprocesador &include( Esta importacin lo Gnico que hace es
incluir el cdigo del (h importado all donde se encuentra la directi%a import(
Esto lle%a a problemas cuando %arios ficheros de cabecera definen un mismo
smbolo# con soluciones poco elegantes( C++ aade adems el concepto de
namespaces que permite agrupar los smbolos de distintos ficheros en un Gnico
espacio de nombres lgico(
En D# como en casi todos los lenguajes modernos# la estructuracin del cdigo
y las bibliotecas se hace usando mdulos y paquetes( Kn mdulo no es ms que
un fichero fuente de cdigo D "generalmente con extensin (d'(
Nmportar smbolos de un mdulo con import
)ara que un mdulo pueda acceder a los smbolos de otro mdulo se usa la
sentencia import,
EEEE inicio modulo/(d EEEE
module modulo/;
int simbolomodulo/ C /-;
EEEE fin modulo/(d EEEE
EEEE inicio modulo1(d EEEE
module modulo1;
import modulo/;
=ritefln" simbolomodulo/ '; 33 correcto
EEEE fin modulo1(d EEEE
Como puede %erse# al contrario de lo que sucede en otros lenguajes# cuando
importamos los smbolos de un mdulo no hace falta anteponer el nombre del
mdulo con un punto antes de llamar a un smbolo; en modulo1 podemos %er
que hemos usado simbolomodulo/ en lugar de modulo/(simbolomodulo/ como
se hara en otros lenguajes( 2 pesar de ello la notacin de modulo(simbolo se
permite tambi8n en D# y es necesaria Gtil cuando se importan dos mdulos que
definen smbolos homnimos para indicar el mdulo del cual queremos usar el
smbolo; no hacerlo as en ese caso es un error de compilacin( 2dems#
tambi8n se puede %er que al principio de cada modulo se usa la palabra
cla%e module seguida del nombre del mdulo( Esta sentencia es opcional y para
mdulos no pertenecientes a paquetes no suele ser necesario pues por defecto
se toma como nombre del mdulo el nombre del fichero sin la extensin( Li
existe# debe ser la primera sentencia "comentarios aparte' del fichero fuente(
static import
Li quieremos que los smbolos importados sean accedidos siempre mediante la
notacin modulo(smbolo usaremos un static import,
EEEE inicio modulo1(d EEE
static import modulo/;
33 =ritefln" simbolomodulo/ '; 33 error
=ritefln" modulo/(simbolomodulo/ '; 33 correcto
import public y pri%ate
+as palabras cla%e public y private antepuestas a un import significan,
public
+os smbolos que se incluyen a tra%8s del import sern a su %e!
exportados a los mdulos que importen el mdulo donde est el import(
private
+os smbolos que se incluyen a tra%8s del import no estarn accesibles
en los mdulos que importen a su %e! el mdulo donde est el import(
Este es el comportamiento por defecto por lo que no es necesario
escribir esta palabra cla%e(
Ejemplo,
EEEE inicio modulo1(d EEEE
import modulo/; 33 pri%ate import por defecto
int simbolomodulo1 C 1-;
=ritefln" simbolomodulo/ ';
EEEE fin modulo1(d EEEE
EEEE inicio modulo. EEEE
import modulo1;
=ritefln" simbolomodulo1 '; 33 correcto# simbolomodulo1 esta definido en
modulo 1
=ritefln" simbolomodulo/ '; 33 error# simbolomodulo/ est definido en
mdulo/#
33 y como modulo. no importa a modulo/ no puede
33acceder al mdulo/ aunque modulo1 lo importe
33y modulo. importe modulo1
)ara que no diera error,
EEEE inicio modulo1(d EEEE
public import modulo/; 33 ahora exportamos todos los smbolos de modulo/
33 como si fueran de modulo1
int simbolomodulo1 C 1-;
EEEE fin modulo1(d EEEE
EEEE inicio modulo. EEEE
import modulo1;
33 correcto# simbolomodulo1 esta definido en modulo 1,
=ritefln" simbolomodulo1 ';
33 correcto porque modulo/ esta importado pGblicamente en modulo1,
=ritefln" simbolomodulo/ ';
*enombrado de mdulos
+os mdulos pueden renombrarse cuando se importan usando el signo igual
con el nue%o nombre a la i!quierda y el nombre del mdulo renombrado a la
derecha,
import corto C mipaquete(directorio(nombreDe5odulo5uy+argo
import selecti%o de smbolos
En lugar de importar todos los smbolos de un mdulo# existe la posiblidad de
importar slo algunos smbolos especficos( Esto es Gtil cuando slo %amos a
usar uno o dos smbolos de un mdulo concreto( +a sintxis para ello es poner
el signo dos puntos con el nombre del mdulo a la i!quierda y la lista de
smbolos que se importan del mismo a la derecha# separados por comas(
33 Llo importamos =ritef y =ritefln de std(stdio
import std(stdio, =ritef# =ritefln
;ambi8n podemos importar smbolos selecti%amente al tiempo que los
renombramos,
33 Llo importamos =ritef y =ritefln renombrando el Gltimo a escribelinea
import std(stdio, =ritef# escribelinea C =ritefln
2cceso a smbolos ocultados por smbolos locales
En ocasiones queremos poder acceder a un smbolo del propio mdulo en el
que est el cdigo que lo usa# pero este puede haberse %isto ocultado por un
smbolo en el alcance local( En ese caso tan slo tenemos que usar la notacin
4punto smbolo4 "(smbolo' que seria equi%alente a hacer
nombredemodulo(smbolo desde otro mdulo que importara el actual,
int simbolo;
%oid funcionconlocal"int simbolo' A
=ritefln" simbolo '; 33 escribe el parmetro simbolo
=ritefln" (simbolo '; 33 escribe el smbolo del mdulo
)aquetes
En ocasiones el cdigo se necesita una estructuracin que %aya ms all de los
mdulos( En ese caso se puede hacer una jerarqua de mdulos bajo un
concepto mayor llamado 4paquete4( )ara declarar que un mdulo est en un
paquete debemos incluir la ruta que debe tener el mdulo dentro de la
jerarqua del paquete# separando los distintos ni%eles de la misma y el nombre
del mdulo "al final' mediante puntos( <eneralmente la jerarqua de los
paquetes suele corresponderse con una organi!acin de directorios y
subdirectorios equi%alente# aunque esto no es estrictamente necesario(
EEEE fichero conexiones(d# que est en el directorio mibiblioteca3red
module mibiblioteca(red(conexiones
33etc
EEEE fichero que est en el directorio mibiblioteca3red3ser%idores
module mibiblioteca(red(ser%idores(http
33etc
Donde se buscan los mdulos y paquetes
Cuando escribimos 4import nombremodulo4 el compilador primero buscar
4nombremodulo(d4 en el directorio actual( De no encontrarlo# si hemos
proporcionado uno o ms parmetros ENdirectorio al compilador
4nombremodulo(d4 se buscar en dichos directorios( Finalmente si tampoco se
encuentra en ellos se buscar en el ENdirectorio que est8 especificado en el
fichero dmd(conf( Cuando se trata de paquetes# si el paquete est organi!ado
por directorios slo es necesario especificar el nombre ra! donde se encuentra
el paquete# no los subdirectorio( )or ejemplo si escribimos import
mibib.red.conexiony el ra! del paquete mibib est en 3usr3include3dmd3mibib
"en el caso de un sistema Knix3+inux35ac' basta con especificar como
parmetro al compilador o en el dmd(conf EN3usr3include3dmd3mibib y el
compilador buscar slo el subdirectorio 4red4 y dentro del mismo el fichero
4conexion(d4(
Compatiblidad de llamada con C
Debido a la difusin del lenguaje# la mayora de las 2)Ns de sistemas operati%os
y libreras de sistemas estn escritas en C u ofrecen una interfa! para el
mismo( D puede acceder a bibliotecas de C( )ara ello# adems de enla!ar con el
fichero binario de la biblioteca mediante parmetros al compilador# debemos
incluir en nuestro cdigo D una declaracin de los smbolos y funciones de C a
los que queramos acceder( Como los tipos de datos de D suelen tener una
correspondencia muy directa con los de C este proceso suele ser bastante
sencillo; sin embargo para con%ersiones de ficheros de cabecera (h ms
complicados se dispone de la herramienta htod que reali!a la con%ersin de
tipos y sintxis de forma automtica# tomando como entrada un fichero (h de C
y generando un fichero (d que podemos incluir en nuestros proyectos(
)ara las declaraciones de smbolos y funciones de C# debemos poner la
instruccin 4extern"C',4( ;omando un ejemplo de la descripcin del htod# si en
un fichero de cabecera (h tu%i8ramos el siguiente cdigo C,
unsigned u;
&define 5ON:; int
%oid bar"int x# long y# long long !';
+a con%ersin del mismo en D sera,
extern"C',
uint u;
alias int 5ON:;;
%oid bar"int x# int y# long !';
Es importante destacar que dentro de un fichero fuente D no podemos incluir
cdigo C "al contrario de lo que sucede en C++('
En la %ersin actGal de D no existe la posibilidad de enla!ar contra bibliotecas
C++(
Delegados# funciones anidadas y funciones
literales
En D existe un tipo de dato llamado 4delegado4 que puede usarse para pasar
referencias a un m8todo de una clase como parmetros para otras funciones y
m8todos( Lon# en concepto# similares a los punteros a m8todo de C++ pero
con una sintaxis tanto de declaracin como de creacin y uso mucho ms
sencilla,
class Foo A
P(((Q
bool es)ar"int :' A return "n H 1 CC -'; D
bool esNmpar"int :' A return R"n H 1 CC -'; D
P(((Q
D
bool %alidadora" bool delegate"int' dlg# int %alor ' A
return dlg"%alor';
D
%oid main"' A
Foo f C ne= Foo"';
bool delegate"int' dlgespar;
bool delegate"int' dlgesimpar;

dlgespar C f(es)ar;
dlgesimpar C f(esNmpar

bool unoespar C %alidadora"dlgespar# /';
bool unoesimpar C %alidadora"dlgesimpar# /';
Como puede %erse en el ejemplo anterior la declaracin de una %ariable que
apunte a un delegado es similar a la de una funcin pero poniendo 4delegate4
en lugar del nombre y el nombre de la %ariable apuntadora al final(
Sablando de funciones y m8todos# D permite tener funciones anidadas y
funciones annimas( +as primeras son funciones que estn definidas dentro de
otra funcin( Lon muy Gtiles para estructurar nuestro cdigo de una forma ms
jerrquica(
+as funciones annimas son funciones "normalmente sencillas' sin nombre que
suelen utili!arse como argumento para una funcin que espera recibir una
funcin como argumento(
Declaracin anticipada de funciones innecesaria
En C y C++ para que una funcin pueda llamar a otra esta debe haber sido
declarada con anterioridad a la misma( )ara ello puede estar el cuerpo
completo de la funcin# o slo un 4prototipo4 que indica los tipos aceptados y el
%alor de%uelto# por ejemplo esto no funcionara,
%oid llamaotra"int prueba' A
funcionprimera" prueba '; 33 error# funcionprimera no est definida
D
%oid funcionprimera"int param' A return param; D
)or lo que tendramos que declarar funcionprimera antes de implementarla# o
directamente implementar 4ms arriba4 de llamaotra( El compilador de D es
algo ms inteligente y hace que esto sea innecesario; cualquier funcin puede
llamar a cualquier otra que est8 definida en el programa# independi8ntemente
de su posicin en el cdigo(
Compilacin condicional y %ersionado sin
necesidad de un preprocesador
En C++# como en C# se utili!a un preprocesador que anali!a el cdigo
reali!ando modificaciones e inclusiones sobre el mismo antes de que se inicie la
compilacin( El preprocesador de C3C++ es antiguo# y adems algunos
programadores parecen disfrutar escribiendo cdigo enre%esado usando las
instrucciones que el mismo proporciona# lo cual lle%a a cdigo bastante ilegible
y dificil de seguir y depurar(
D elimina completamente el preprocesador y en lugar de esos aade una serie
de directi%as para el compilador pero incluidas en el lenguaje que nos permiten
darle indicaciones sobre que cdigo compilar segGn unos parmetros
determinables en tiempo de compilacin(
Estas directi%as son,
module
Con esta intruccin indicamos el uso desde nuestro programa de otros mdulos
en C "%er ms adelante el apartado sobre mdulos y paquetes para %er una
descripcin ms completa' y por lo tanto sustituira al &include de C3C++( 2l
contrario de lo que sucede con el &include no hay ningGn problema en que
%arios mdulos incluyan a un mismo smbolo a tra%8s de importaciones# por lo
que el chapucero cdigo siguiente# tan necesario en C3C++ para proyectos
complicados que in%olucran muchas inclusiones# es innecesario en D,
&ifndef T;E:E5@LT5@DK+@T
33cdigo del mdulo
&define T;E:E5@LT5@DK+@T
&endif
33:ada
%ersion
@tro uso muy comGn del preprocesador de C3C++ es la supresin o no de
determinados bloques de cdigo segGn parmetros pasados al compilador o
incluidos en el entorno del mismo( )or ejemplo en C3C++ cuando queremos
que un cdigo se compile en Uindo=s o +inux hacemos,
&ifdef linux
printf"4estoy en linuxR4';
&ifdef =indo=s
printf"4estoy en =indo=sR4';
En este caso la definicin 4linux4 o 4=indo=s4 lo proporciona el compilador#
pero igualmente se pueden suminitrar al mismo definiciones adicionales usando
la linea de comandos del mismo(
En D para hacer esto mismo# pero con ms elegancia# se usa la
instruccin version,
%ersion"linux'A
printf"4Estoy en linuxR4';
D
%ersion"=indo=s'A
printf"4Estoy en =indo=sR4';
D
)odemos definir los smbolos comprobables mediante la intruccin %ersion
usando parmetros al compilador "E%ersionCshare=are' o podemos generar
nue%os smbolos dentro del cdigo# siempre usando bloques e%aluables en
tiempo de compilacin# como el incluido dentro de otro bloque %ersion# usando
asignaciones,
%ersion"share=are' A
%ersion C puedeleer;
D
%ersion"comercial' A
%ersion C puedeleer;
%ersion C puedeescribir;
%ersion C puedeimprimir;
D
%ersion"puedeleer' A
33Nmplementacin de la funcionalidad de lectura
D
%ersion"puedeescribir' A
33Nmpplementacin de la funcionalidad de escritura
D
%ersion"puedeimprimir' A
33Nmplementacion de la funcionalidad de impresin
D
En el ejemplo anterior# al compilar especificaremos como parmetro al
compilador 4%ersionCshare=are4 o 4%ersionCcomercial4 segGn la %ersin del
programa que queramos que se genere(
debug
+a instruccin debug es muy similar a version pero en lugar de usarse para
especificar caractersticas del entorno o funcionalidades se usa para incluir
dentro del bloque cdigo de depuracin que nos ayude a detectar y corregir
errores en %ersiones en desarrollo( Lustituye a otro uso tradicional del
preprocesador en C3C++,
&define DE?K<
33codigo normal
&ifdef DE?K<
33codigo de depuracion
&endif
En D el cdigo equi%alente sera,
debug C si
33cdigo normal
debug"si' A
33cdigo de depuracin
D
+a intruccin debug adems de aceptar como parmetro un posible
identificador# acepta %alores enteros( En ese caso se compilarn todos los
bloques debug cuyo parmetro sea igual o menor al %alor entero( )or ejemplo,
debug C 1
33 cdigo normal
debug"/' A
33 cdigo de depuracin de ni%el /
D
debug"1' A
33 cdigo de depuracin de ni%el 1
D
debug".' A
33 cdigo de depuracin de ni%el .
D
En el ejemplo anterior# como debug %ale 1# se ejecutarn los dos primeros
bloques de depuracin "los que tienen como parmetro / y 1'# pero no se
ejecutar el tercero( Esto es Gtil para incrementar escalar la salida de
diagnstico de nuestro programa en %arios ni%eles# siendo las mayores las que
ms salida mostrarn(
static if
El static if se usa para comprobar el %alor de smbolos e%aluables en tiempo de
compilacin# como constantes o alias( Es similar a %ersion# pero permite una
mayor flexibilidad al poder usarse en instanciaciones de templates(
const int bitsint C /V;
static if "bitsint CC /V'
alias short N:;;
else static if "bitsint CC .1'
alias int N:;;
static assert
El static assert funciona igual que el assert pero comprobado slo %alores
e%aluables en tiempo de compilacin( En caso de que la condicin e%alue a un
%alor falso# el programa no se compilar(
2rrays mucho ms manejables y foreach
+os arrays "o matrices# o %ectores# como se quieran traducir' en C++ son
exactamente los mismos que en C# es decir# un poco de a!Gcar sintctico para
un puntero a una memoria asignada( El a!Gcar sintctico sin embargo no es
mucho# y para reali!ar algunas operaciones bsicas "como aadir o quitar
elementos a un array o cambiar su tamao' debemos hacer engorrosas
llamadas para asignar e iniciali!ar nue%a memoria( +a cosa empeora si
pensamos que adems las 4cadenas4 en C estn implementadas como un array
de caracteres sin ninguna propiedad especial(
C++ soluciona parte de estas limitaciones a tra%8s de su librera estndar de
plantillas "L;+' que proporciona plantillas de clase gen8ricas para di%ersas
estructuras de datos con mGltiples operaciones# adems %arias clases
a%an!adas para cadenas(
En D# adems de existir una biblioteca de plantillas de clase a%an!adas "la D;+#
actualmente en desarrollo' los arrays cuentan con una serie de caractersticas
que los hacen mucho ms prcticos y manejables que los de C3C++,
Cuentan con comprobacin de lmites(
)ueden redimensionarse dinmicamente cambiando su propiedad
4length4 o aadiendo al final con el operador 4WC4(
)ueden concatenarse fcilmente dos o ms arrays en uno slo con el
operador 4W4(
)ermiten la especificacin de subrangos dentro de un array( )or
ejemplo si quisi8ramos los elementos .# X y Y de un array en un subarray
podramos hacer, subarray C miarrayP.((YQ( Esto adems permite copiar de
forma sencilla los arrays por %alor con la siguiente notacin, int array1PQ C
array/PQ; +os rangos tambi8n permiten asignaciones automticas a %arios
elementos de un array simultaneamente, arrayP1((VQ C -;
2dems de la propiedad length# ya comentada# cuentan con otras
propiedades Gtiles "como si!e para el tamao# dup para crear un duplicado#
re%erse para in%ertir el orden de los elementos y sort para ordenarlos('
+os arrays estticos "en los que en la declaracin indicamos el
tamao de cada dimensin como en intP.QPXQ matri!; se implementan como
las matrices de fortran en lugar de como punteros a punteros; esto hace
que sean mucho ms eficientes a la hora de calcularlos( +os arrays
dinmicos "intPQPQ matri!;' sin embargo s que se implementan como en C#
como punteros a punteros( )or lo tanto si necesitamos hacer clculos de
matrices extremadamente rpidos es aconsejable usar los arrays estticos(
En general todas estas caractersticas hacen que los arrays en D se manejen de
la forma ms intuiti%a y no haya que estar recordando constantemente que su
implementacin es poco ms que un puntero con longitud "que lo es('
Cadenas
Kna consecuencia directa de estos arrays mejorados es que las cadenas
nati%as# a pesar de seguir siendo arrays de caracteres# son ahora infintamente
ms manejables( +o Gnico que tenemos que tener en consideracin es que los
literales de cadena "caracteres entre comillas' son arrays inmutables# esto es#
que no pueden ser modificadas y como D no deja asignar entre objetos
mutables e inmutables sin hacer con%ersiones# no podemos asignar los literales
de cadena a arrays de char si no los declaramos mutables( Esto que suena tan
lioso lo %amos a %er enseguida con un par de ejemplos,
charPQ cadena5utable; 33 Cadena es un array de caracteres mutable;
charPQ otraCadena5utable;
cadena5utable C 4hoyganR4; 33 E**@*, 4hoyganR4 como literal de cadena es
inmutable y no podemos asignarlo a un mutable
otraCadena5utable C 4hoyganR4(dup 33 Correcto# dup crea una copia
mutable del literal

)ara asignar literales de cadena sin llamar a (dup podramos declarar a los
arrays de caracteres como in%ariantes,
in%ariant"char'PQ cadenaNnmutable C 4hoyganR4; 33 Correcto# asignamos un
inmutable a otro
in%ariant"char'PQ otraCadenaNnmutable C cadena5utable; 33 E**@*#
asignando mutable a inmutable
in%ariant"char'PQ ultimaCadenaNnmutable C cadena5utable(idup; 33
Correcto# idup crea una copia inmutable

Como esta sntaxis es un poco fea para manejar cadenas y D es un lenguaje
orientado principalmente a la practicidad# se ha creado un alias
a in%ariant"char'PQ llamado string# de modo que el ejemplo anterior quedara
como,
string cadenaNnmutable C 4hoyganR4; 33 Correcto# asignamos un inmutable a
otro
string otraCadenaNnmutable C cadena5utable; 33 E**@*# asignando mutable
a inmutable
string ultimaCadenaNnmutable C cadena5utable(idup; 33 Correcto# idup crea
una copia inmutable

Como he comentado al principio de este punto# las cadenas al no ser ms que
arrays de char en D pueden tienen las mismas operaciones que 8stos "y el
mismo rendimiento'# por lo tanto podemos ol%idarnos del infierno de las
cadenas en C,
33 2signacin
cadena/ C cadena1;

33 Copia
string cadena/ C cadena1(dup; 33


33 Copia de subcadenas
string cadena/ C 4Soygan amijosR4;
string cadena1 C cadena/P-((YQ; 33 cadena1 C 4Soygan4

33 Concatenacin
string cadena. C cadena/ W cadena1;


33 2adir al final
string cadenaX C 4SoyganR 4;
cadenaX WC 4amijosR4;

33 Comparacin
if "cadena/ Z cadena1' (((

Casi casi igual que en el infierno de punteros y ne=s de C o la %erborrea infame
de $a%a o las L;+ 6%erdad9
2rrays asociati%os
D tambi8n cuenta con un tipo de dato deri%ado del array llamado array
asociati%o que consiste en una estructura de datos "nati%a' que asocia una
cla%e con un %alor# de forma que despu8s conociendo la cla%e podamos
recuperar el %alor( ;anto la cla%e como el %alor pueden ser de cualquier tipo y
la forma general de declarar un array asociati%o es muy sencilla,
tipo[alorPtipoCla%eQ;
)or ejemplo para declarar un array asociati%o en el que las cla%es fueran
enteros y los %alores objetos de tipo 45iClase4,
5iCla%ePintQ;
@ uno con cla%es de tipo entero y %alores de tipo cadena,
intP string Q;
7uien tenga algo de experiencia programando seguramente reconocer la
utilidad de este tipo de estructuras de datos# probablemente una de las ms
utili!adas en programacin "con permiso de las listas3%ectores'# por ello casi
todos los lenguajes de programacin ofrecen al programador la posibilidad de
usar este tipo( $a%a# C& y C++ no son una excepcin# pero a diferencia de D en
estos lenguajes el tipo de array asociati%o "y sus %ariantes' estn
implementados como clases en la biblioteca estndar por lo que por un lado el
rendimiento nunca %a a ser el mismo que el de un tipo nati%o "optimi!able
hasta la muerte por el compilador# que sabe manejarlo mejor que una clase' ni
por otro lado ser igual de cmodo# aunque esto sea menos importante "en el
caso de estos lenguajes tendremos que declarar un objeto# construirlo con ne=
y despu8s utili!ar m8todos para acceder a sus elementos( C++ usando
sobrecarga de operadores permitir usar las instancias con notacin de array#
pero la declaracin y construccin debern seguir reali!ndose como objetos de
clase; objetos de clase de plantilla# para ser exactos('
+os arrays asociati%os de D adems de algunas de las propiedades de los arrays
normales# cuentan con algunas adicionales,
)odemos llamar a su miembro remo%e"cla%e' para eliminar una cla%e
del array(
)odemos usar el operador in para comprobar si una cla%e est en un
array "if"4polompos4 in mi2rray'((('
+a propiedad (Jeys de%ol%er un array normal que contendr todas
las cla%es(
+a propiedad (%alues de%ol%er un array normal que contendr todos
los %alores(
2parte de estos tipos nati%os "arrays y arrays asociati%os' D tambi8n contar
con una librera de estructuras de datos gen8ricas que proporcionar
estructuras de datos ms a%an!adas llamada la 4D template library4 en intenso
desarrollo en el momento de escribir este artculo(
foreach y foreachTre%erse
Kna de las operaciones ms comunes con arrays es recorrerlos mediante un
bucle for como en el siguiente ejemplo,
for "int i C -;i \ /-; ++i' A
printf"42rrayPHdQ, Hd4# i# miarrayPiQ';
D
D aade una palabra cla%e "heredada de otros lenguajes' que nos permite
recorrer los arrays u otros contenedores obteniendo en cada iteracin el
siguiente elemento en lugar de un ndice que luego tendramos que usar para
direccionar cada elemento dentro del bucle( Esto elimina# en la mayor parte de
los casos# la necesidad de tener que usar incmodos iteradores# comprese por
ejemplo,
;ipoContenedor,,iterator sl;
for" sl C instanciaContEZbegin"'; sl RC instanciaContEZend"'; ++sl'
A
"Bsl'EZimprimir[alor"';
D
o(((
;ipoContenedorNterator it"BinstaciaCont';
;ipoDato Bp;
=hile" "p C it(current"'' RC -'
A
++it;
pEZimprimir[alor"';
D
Con la construccin equi%alente en D usando foreach,
foreach";ipoDato t; instanciaCont'
A
t(imprimir[alor"';
D
En D# por supuesto# tambi8n pueden usarse iteradores para formas menos
comunes de recorrer los bucles permitiendo toda la potencia de los iteradores
4tradicionales4 pero rara %e! son necesarios porque habitualmente las propias
implementaciones de los contenedores permiten recorrerlos de distintas
formas,
33 *ecorrer in%ertido,
foreach";ipoDato t; instanciaCont(re%erse"''
A
t(imprimir[alor"';
D
33 *ecorrer in%ertido los %alores dobles y pares,
foreach";ipoDato t; instanciacont(filter"pares'(transform"doblar'(re%erse"''
A
t(imprimir[alor"';
D
En el Gltimo ejemplo hemos utili!ado dos m8todos de las instancias de el tipo
de dato que estbamos utili!ando que aceptan un argumento funcin o
delegado "m8todo' para reali!ar# en el primer caso una seleccin de los
elementos pares Gnicamente y el segundo dobla los elementos que queden
despu8s de la primera transformacin( Como puede %erse esto no hace nada
que no pueda hacerse con iteradores# pero la sintaxis es mucho ms clara y
concisa "de nue%o# si realmente necesitamos de iteradores tambi8n
dispondremos de ellos en D('
+os m8todos mostrados en los Gltimos ejemplos estn implementados en las
estructuras de datos de la librera D;+ que probablemente formar parte en el
futuro# como librera de estructuras de datos# de la librera estndar de D(
;ambi8n contamos con foreachTre%erse que recorre un contenedor del final al
inicio por lo que la llamada a re%erse"' del ejemplo anterior no sera realmente
necesaria si usramemos foreachTre%erse en lugar de foreach(
*;;N "identificacin de tipos en tiempo de
ejecucin'
De cuenta con un sencillo mecanismo de *;;N; los objetos disponen de una
propiedad 4classinfo4 la cual contiene algunas propiedades de la clase que se
pueden %er completamente en el cdigo del fichero object(d "en general es
aconsejable %er ese fichero fuente para %er las capacidades por defecto del
objeto ra! de D(' Estas propiedades son,
init, Nniciali!ador esttico de clase(
name, :ombre de la clase
%tbl, 2rray de punteros a las funciones %irtuales
base, @bjeto classinfo de la clase padre
destructor, )untero al destructor
deallocator, )unto al desasignador de memoria(
defaultContructor, )untero al constructor por defecto
find "m8todo', 6)ara buscar en la jerarqua de la clase9
+a %ersin actual de D no soporta reflexin dentro del lenguaje# aunque algunas
libreras de terceros lo estn implementando fuera del mismo# por
ejemplo Flectioned(
)osibilidad de ejecucin de cdigo como si fuera
un lenguaje interpretado
+os lenguajes interpretados cuentan con la %entaja de que es muy fcil escribir
unas lneas de cdigo en un editor y ejecutar el int8rprete sobre el mismo# o
inclGir en los sistemas Knix3+inux35ac como primeras lneas el nombre del
int8rprete para permitir su ejecucin como si de un ejecutable se tratase(
Esta segunda posibilidad est incorporada en D mediante el parmetro al
compilador 4Erun4 que compila# enla!a y ejecuta el cdigo que se le pase# sin
generar ningGn ejecutable en el disco( Ello nos permite crear scripts rpidos
que se ejecuten como si de un lenguaje interpretado se tratase simplemente
teniendo como primeras lneas,
&R3usr3bin3dmd Erun
P*esto de cdigo DQ
El compilador de D de Digital 5ars es adems sorprendentemente rpido# por lo
que incluso ejecutndose de esta forma el resultado en ocasiones puede ser
ms rpido que usando un lenguaje de script real "como )ython o )erl('
)ropiedades
Con este tema %oy a expandirme un poco ms de que sera necesario para
explicar las propiedades en D# en mi intento de intentar educar a algunos
programadores recalcitrantes(
5uchos programadores inteligentes estarn hasta las narices de leer y escribir
4getters4 y 4setters4# que son miembros de clases cuya utilidad es 4obtener4
"get' o 4establecer4 "set' el %alor de un miembro de una clase( De esto se
abusa terriblemente# sobre todo programadores pro%enientes de los mundos
$a%a y C++# dndose en la realidad casos absurdos como,
33 C++# para no mancillar el D con este ejemplo,
33 )ersona(h,

class )ersona A
public,
%oid )ersona"string nombre# string apellidos';

string get:ombre"';
%oid set:ombre"string nombre';

string get2pellidos"';
%oid set2pellido"string apellidos';
pri%ate,
string mTnombre;
string mTapellidos;
D

33 )ersona(cpp,

%oid )ersona,,)ersona"string nombre# string apellidos' A
mTnombre C nombre;
mTapellidos C apellidos;
D

string get:ombre"' A
return mTnombre;
D

%oid set:ombre"string nombre' A
mTnombre C nombre;
D

string get2pellidos"' A
return mTapellidos;
D

string set2pellidos"string apellidos' A
mTapellidos C apellidos;
D

33 main,
)ersonaB juan C ne= )ersona"4$uan4# 42l%are! 5artine!4';
juanEZset:ame"4$uanjo4';
juanEZset2pellidos"42l%are! 5artine!4';
cout \\ 4:ombre de la persona, 4 \\ juanEZget:ame"';
cout \\ 42pellidos, 4 \\ juanEZget2pellidos"';
En realidad# si sabemos que nunca %amos a reali!ar operaciones sobre el
nombre o los apellidos antes de asignarlos y# sobre todo# antes de de%ol%erlos
6porque escribimos un par de m8todos para usar esos miembros9 Li lo
pensamos bien# en la mayora de las clases que hemos escrito o %isto de esta
forma# el ]YH de los getters3setters que en origen tienen esta forma jams
harn ninguna operacin aparte de asignar el %alor o de%ol%erlo directamente(
Es decir# esta clase podra haberse escrito directamente as,
33 En D# al ser un ejemplo ms digno# adems as no hay que escribir dos
ficheros,

class )ersona A
public,
this"string nombrearg# string apellidosarg' A
nombre C nombrearg;
apellidos C apellidosarg;
D

string nombre;
string apellidos;
D

33 Ksaremos esto como,
)ersona juan C ne= )ersona"4$uan4# 42l%are! 5artine!4';
juan(nombre C 4$uanjo4;
juan(apellidos C 42l%are! 5artine! ;orres $imene!4;
=ritefln"4:ombre, 4# juan(nombre';
=ritefln"42pellidos, 4# juan(apellidos';

Nmagino que muchos programadores de $a%a y C++ estarn tras %er este
ejemplo respirando en una bolsa de plstico# sin embargo# aparte de que estas
construcciones son muy frecuentes en lenguajes ms modernos como )ython#
si lo pensamos detenidamente no tiene ningGn sentido escribir funciones
alrededor de %ariables cuyo %alor nunca se %a a modificar dentro de dichas
funciones( :inguno en absoluto( Le que alguno estar arandose la cara y
gritando mientras mira al cielo "La encapsulacin, la encapsulacin!" como si la
encapsulacin fuera el Dios de una religin que hay que seguir por una cuestin
de fe# pero es que resulta que no estamos rompiendo ninguna encapsulacin
porque este "adorado por algunos' t8rmino no significa ms que encapsular un
miembro de la clase y# asignar directamente un %alor y de%ol%erlo sin hacerle
nada no encapsula nada en absoluto( O hace que el cdigo sea ms lento# por
cierto(
Say sin embargo un argumento bastante bueno castigar al usuario de nuestra
clase haci8ndole escribir getters y setters infinitos, aunque en la %ersin actual
de la clase no reali!emos ninguna operacin al obtener o de%ol%er el %alor
miembro# es posible que en el futuro s queramos hacerlo( )or ejemplo
podemos querer asegurarnos de que la primera letra del nombre y los apellidos
sea mayGscula# o que al de%ol%er el nombre aadamos el 4Don4 o 4Doa4( En
realidad aunque muchos se agarren a este argumento la inmensa mayora de
getters y setters que empie!an %acos pasa el resto de sus das %acos( )ero
ante la duda# incluso programadores ms racionales y menos dogmticos# usan
los getters del demonio para e%itar el riesgo de romper la interfa! de la clase en
el futuro(
)ropiedades al rescate( +as propiedades en D y otros lenguajes son unas
construcciones que nos permiten ofrecer al usuario de la clase una interfa!
sencilla "juan(nombre C 4$uanjo4; =ritefln"juan(nombre';' pero al mismo
tiempo nos permiten tener la posibilidad de reali!ar operaciones adems de la
asignacin o de%olucin del %alor# si as lo estimamos oportuno( O lo mejor de
todo es que nos permiten no escribir funcin alguna# usando un miembro
pGblico# mientras no se realicen esas operaciones adicionales# y todo ello sin
romper nunca la interfa! de nuestra clase( Li repasamos el ejemplo anterior#
podramos pensar que si en la %ersin 1(- de )ersona queremos que al
asignarse )ersona(nombre se ponga siempre la primera letra en mayGscula no
podemos hacerlo sin meter los gesetters del infierno( )ero usando propiedades
s podemos,
33 En D# al ser un ejemplo ms digno# adems as no hay que escribir dos
ficheros,
import std(string;

class )ersona A
public,
this"string nombrearg# string apellidosarg' A
nombre C nombrearg;
apellidos C apellidosarg;
D

string nombre"' A return mTnombre; D 33 4<etter4
%oid nombre"string nombrearg' A
mTnombre C capitali!e"nombrearg';
D

pri%ate,

string mTnombre;
string mTapellidos;
D

33 O el usuario lo sigue usando# E^2C;25E:;E N<K2+# pero
33 ntese como pone la primera letra mayGscula

)ersona juan C ne= )ersona"4$uan4# 42l%are! 5artine!4';
juan(nombre C 4juanjo4;
juan(apellidos C 42l%are! 5artine! ;orres $imene!4;
=ritefln"4:ombre, 4# juan(nombre'; 33 Nmprime 4$uanjo4# no 4juanjo4
=ritefln"42pellidos, 4# juan(apellidos';

Linceramente# el que no %ea la belle!a y elegancia de esto y siga prefiriendo los
gesetters al estilo tradicional# mejor que se dedique a una profesin donde no
haya que e%olucionar tanto como en la programacin(
Nota: este artculo se ir ampliando con secciones sobre:
Lobrecarga de operadores
El pseudotipo 4auto4
:ue%a sintaxis para gen8rica
)rogramacin por contratos "unittest# inAD# outAD y dems'
Lignals y slots
5odulos strings
2mpliar cadenas CZ =ritefln# readln# secuencias de escape# etc
Comentarios "de documentacin y anidados'
http,33===(dsource(org3projects3tutorials3=iJi3;utorialFundamentals
ms recursos, dsource# digitalmars(com3d# pro=iJi(org#
http,33===(pro=iJi(org3=iJiXd3=iJi(cgi9DTT;utorial# h1d# dui# descent# d=t#
)hobos
D;+
Silos "sincroni!acion'
;ipo de herencia# m8todos %irtuales y mixins