Visão Geral
O que é D?
D é uma linguagem de programação de sistemas e aplicações de propósito geral. Ela tem um nível mais alto que C++, mas retém a habilidade de escrever código de alto desempenho e interfacear diretamente com as API's do sistema operacional e com o hardware. D é bem-vindo para escrever programas de média e grande escala com milhões de linhas e com times de desenvolvedores. D é fácil de aprender, provê muitas facilidades para ajudar o programador, e é bem-vinda para agressiva técnologia de otimização do compilador.D não é uma linguagem de script, nem uma linguagem interpretada. Não vem com uma VM, uma religião, pu uma filosofia de anulação. É uma linguagem prática para programadores práticos que precisam ter o trabalho feito rapidamente, com confiança, e deixar manutenção para trás, fácil para entender o código.
D é a culminação de décadas de experiência implementando compiladores para muitas linguagens diversas, e tentando construir grandes projetos usando essas linguagens. D tira inspiração dessas outras linguagens (mais especialmente C++) e tempera-a com experiência e prática do mundo real.
Por que D?
Por que afinal. Quem precisa de outra linguagem de programação?A indústria de software teve um longo caminho desde que a linguagem D foi inventada. Muitos novos conceitos foram adicionados à linguagem com C++, mas compatibilidade passada com C foi mantida, incluindo compatibilidade com quase todas as fraquezas do projeto original. Houveram muitas tentativas de consertar essas fraquezas, mas a questão de compatibilidade frustrou-as. Enquanto isso, C e C++ sofreram constante acrescimo de novas características. Estas novos características devem caber na estrutura existente sem requerer reescrever coódigo antigo. O resultado final é muito complicado - o padrão C tem aproximadamente 500 páginas, eo o padrão C++ tem mais de 750 páginas! C++ é uma linguagem difícil e cara para implementar, resultando em variações de implementações que tornam frustrante escrever código C++ totalmente portável.
Programadores C++ tendem a programar em ilhas particulares da linguagem, isto é, tornando muito proficiente usar certas características enquanto evitar outros conjuntos de características. Enquanto o código é normalmente portável de compilador para compilador, pode ser difícil portá-lo de programador para programador. Uma grande força de C++ é que ele pode suportar muitos estilos de programação diferentes - mas em termos de muito uso, os estilos sobrepostos e contraditórios são um obstáculo.
C++ implementa coisas como vetores redimensionáveis e concatenação de strings como parte da biblioteca padrão, não como parte da linguagem núcleo. Não ser parte da linguagem núcleo tem muitas conseqüências de subdesempenho.
Pode o poder e capacidade de C++ ser extraído, re-projetado, e reformado em uma linguagem que seja simples, ortogonal e pratica? Pode tudo isso ser posto em um pacote que seja fácil para escritores de compiladores implmentarem corretamente , e que permita aos compiladores gerar códifo agrssivamente otimizado?
Moderna técnologica de compiladores tem progredido ao ponto onde características da linguagem para o propósito de compensar técnologias de compiladores primitivos podem ser omitidas. (um exemplo disso seria a palavra 'register' em C, um exemplo mais sútil é o pré-processador de macro em C.) Nós podemos confiar em modernas técnologias de otimização do compilador para não precisar de características da linguagem para obter código de qualidade dos compiladores primitivos.
Principais Metas de D
- Reduzir os custos de desenvolvimento de software em ao menos 10% pela adição de produtividade comprovada realçando características e ajustando características da linguagem de modo que erros comuns, bugs consumindo tempo sejam eliminados do começo.
- Torná-la fácil para escrever código que seja portável de compilador para compilador, máquina para máquina, e sistema operacional para sistema operacional.
- Suportar multi-paradigmas de programação, isto é, com um mínimo de suporte a paradigmas imperativos, estruturados, orientados a objetos, e programação genérica.
- Ter uma curta linha de aprendizagem para programadores confortáveis com programação em C ou C++.
- Tornar D substâncialmente mais fácil para implementar um compilador próprio que C++.
- Ser compatível com as APIs C locais.
- Ter uma gramática livre de contexto.
- Facilmente suportar escrever aplicções internacionalizadas.
- Incorporar metodologia de Programação de Contrato e teste de unidade.
- Ser capaz de construir programas leves sozinho.
- Reduzir os custos da criação de documentação.
Características para Manter de C/C++
O olhar geral de D é como C e C++. Isto torna mais fácil de aprender e portar código para D. Transição de C/C++ para D deveria ser natural. O programador não terá que aprender um modo inteiramente novo de fazer as coisas.Usar D não significa que o programador ficará restrito a uma vm (virtual machine - máquina virtual) especializada como a vm do Java vm ou a vm do Smalltalk. Não há uma vm para D, é um compilador direto que gera arquivos objeto linkaveis. D se conecta ao sistema operacional como C faz. As ferramentas familiares como make se encaixarão corretamente no desenvolvimento em D.
- O look and feel geral de C/C++ é mantido. Ele usa a mesma sintaxe algébrica, a maioria das mesmas expressões e formas de instruções, e o layout geral.
- Programas em D podem ser escritos no estilo C função-e-dados, estilo C++ orientado-a-objetos, estilo C++ metaprogramação de gabaritos, ou qualquer mistura das três.
- O modelo de desenvolvimento compile/link/depure é levado adiante, embora nada impeça D de ser compilado em bytecode e interpretado.
- Tratamento de Exceções. Mais e mais experiência com tratamento de exceções mostra que há um modo superior de tratar erros que o método tradicional de C usando códigos de erros e errno globais.
- Identificação de Tipo em Tempo de Execução. Isto é parcialmente implementado em C++; em D é levado a seu próximo passo lógico. Suporte completo habilita melhor coleta de lixo, melhor suporte do depurador, persistência mais automatizada, etc.
- D mantém links de funções compatíveis com as convenções de chamada deC. Isto torna possível para programas em D acessar APIs do sistema operacional diretamente. O conhecimento dos programadores e experiência com APIs de programação e paradigmas existentes pode ser levada adiante para D com esforço mínimo.
- Sobrecarga de Operadores. Programas em D podem sobrecarregar operadores possibilitando extensão dos tipos básicos com tipos definidos pelo usuário.
- Metaprogramação de Gabaritos. Gabaritos são um modo de implementar programação genérica.Putros modos incluem usar macros ou ter um tipo de dados variante. Usar macros está fora. Variantes são diretos, mas ineficiêntes e falta verificação de tipo. As dificuldades com gabaritos em C++ são sua complexidade, eles não se ajustam bem na sintaxe da linguagem, todas as varia regras para conversões esobrecarga providas sobre isso, etc. D oferece um modo muito mais simples de fazer gabaritos.
- RAII(Resource Acquisition Is Initialization). Técnicas RAII são um componente essencial para escrever um software seguro.
- Programação baixa e suja. D retém a abilidade de fazer programação baixa-e-suja sem recorrer à referências à módulos compilados em uma linguagem diferente. Algumas vezes, é necessário coagir um ponteiro ou imergir em assembly quando fazendo trabalhos de sistema. A meta de Dnão é previnir progrmação baixa e suja, mas minimizar a necessidade dela resolvendo tarefas de codificação rotineiras.
Características para Derrubar
- Compatibiliadade com código fonte em C. Extensões de C que mantém compatibilidade com código fonte já foram feitas (C++ e ObjectiveC). Mais trabalho nessa área é impedido por tanto código legado e é improvável que possam ser feitas melhorias significantes.
- Compatibilidade de lingação com C++. O modelo de objeto em tempo de execução do C++ também é complicado - suportar isso corretamente implicaria em fazer de D um compilador C++ completo também.
- O pré-processador de C. Processamento de macro é um jeito fácil de extender uma linguagem, adicionando características falsas que não estão lá realmente (invisível para o depurador simbolico). Compilação condicional, camadas com textos #include, macros, concatenação simbólica, etc., essecialmente não formam uma linguagem mas mas duas fundidas se uma distinção óbvia entre elas. Até pior (ou talvez para melhor) o pré-processador de C é uma inguagem de macro muito primitiva. É hora de pisar atrás, olhar para que o pré-processador é usado, e projetar suporte para essas capacidades diretamente na linguagem.
- Herança múltipla. É uma característica complexa de valor datável. É muito difícil implementar de forma eficiênte, e compiladores são propensos a muitos bugs implementando isso. Quase todo valor da EM pode ser controlado com herança simples acoplada com interfaces e agregação. O que parte não justifica a implementação de EM.
- Espaços de Nomes. Uma tentativa de lidar com problemas resultantes de unir pedaços de código desenvolvidos independentmente que tem conflitos de nomes. A idéia de módulos é simples e trabalha muito melhor.
- espaço de nome de etiqueta. Esta característica de C é onde o rotulo que nomeia a estrutura está em uma tabela de símbolos separada mas paralela. C++ tentou fundir o espaço de nome de etiqueta com o espaço de nome regular, enquanto manteve compatibilidades passadas com código legado de C. O resultado é desnecessáriamente confuso.
- Declarações dianteiras. Compiladores C só conhecem o que lexicamente precedeu o estado atual. C++ extende isso um pouco, em que membros de classes podem confiar em membros de classe referenciados adiante. D leva isso a sua conclusão lógica, declarações dianteiras não são necessárias a nível de módulo. Funções podem ser definidas em uma ordem natural no lugar da típica ordem dentro-fora comumente usada em programas C para evitar escrever declarações dianteiras.
- Incluir arquivos. Uma causa pricipal de compilar lentamente como cada unidade de compilação deve analisar enormes quantidades de arquivos. Incluir arquivos deveria ser feito como importar uma tabela de símbolos.
- Trigrafos e digrafos. Unicode é o futuro.
- Funções-membro não-virtuais. Em C++, um projetista de classe con antecedencia se uma função é para ser virtual ou não. Esquecer de marcar a função-membro da classe base para ser vertual quando a função deve ser anulada é um erro comum (e muito difícil de achar) de codificação. Fazer todas as funções-membro virtuais, e deixar o compilador decidir se não há anulações e conseqüêntemente pode ser convertida para não-virtual, é muito mais seguro.
- Campos de bits de tamanho arbitrário. Campos de bits são uma característica complexa e eneficiênte raramente usada.
- Suporte para computadores de 16 bits. Nenhuma consideração é dada em D para ponteiros perto/longe misturados e todas as maquinações necessárias para gerar bom código de 16 bits. O projeto da linguagem D assume que ao menos um plano de espaço de memória de 32 bits será usado. D se ajustará suavemente em arquiteturas de 64 bits.
- Dependência mútua de passagens do compulador. Em C++, analisar o texto fonte com sucesso depende de ter uma tabela de símbolos, e em vários comandos do pré-processador. Isto torna impossível pré-analisar fonte em C++, e torna escrever código para analisadores e editores diretos de sintaxe dolorosamente difícel de serem feitos corretamente.
- Complexidade do compilador. Reduzindo a complexidade de uma implementação torna mais provável que mútiplas implementações, corretas estejam disponíveis.
- Distinção entre . and ->. Esta distinção é realmente desnecessária. O operador . serve bem para derreferênciar ponteiros.
D é para quem
- Origramadores que habitualmente usam lint ou ferramentas de análise de código similares para eliminar bugs antes mesmo de o código ser compilado.
- Pessoas que compialm com máximo de níveis de advertência ligados e que instruem o compilador a tratar advertências como erros.
- Gerêntes de programação que são forçados a confiar em diretrizes de estilo de programação para evitar bugs comuns do C.
- Aqueles que decidem que a promessas da programação orientada a objetos do C++ não são totalmente cumpridas devida à complexidade delas.
- Programadores que desfrutamdo expressivo poder de C++ mas estão frustrados pela necessidade de gastar muito esforço gerênciando memória e procurando bugs.
- Projetos que precisam de teste e verificação nativos.
- Times que escrevem aplicações com milhões de linhas de código.
- Programadores que pensam que a linguagem deveria porver várias características para obviar a necessidade contínua de manipular ponteiros diretamente.
- Programadores numéricos. D tem muitas características para suportar diretamente características necessárias para programadores numéricos, como suporte direto para o tipo de dados complexo e comportamento definido para NaN's e infinitos. (Estes foram adicionados no novo padrão C99, mas não em C++.)
- O analisador léxico e gramatical de D são completamente independentes de outros e do anlisador semântico. Isso significa que é fácil escrever ferramentas simples para manipular fonte em D perfeitamente sem ter que construir um compilador completo. Também signific que código fonte pode ser transmitido em forma simbolica para aplicações especializadas.
D não é para quem
- Realmente, ninguém irá converter programas de milhões de linhas em C ou C++ para D, e como D não compila código fonte C/C++ imodificado, D não é para aplicações legadas. (Porém, D suporta APIs C legadas muito bem.)
- Programas muito pequenos - uma linguagem de script ou interpretada como Python, DMDScript, ou Perl é provavelmente mais satisfatória.
- Como uma primeira linguagem de programação - Basic ou Java são mais satisfatórias para iniciantes. D é uma excelente segunda linguagem para programadores intermediários e avançados.
- Puristas de linguagens. D é uma linguagem prática, e cada característica dela é avaliada nessa luz, ao invés de por um ideal. Por exemplo, D tem construções e semânticas que virtualmente eliminas a necessidade de ponteiros para tarefas ordinárias. Mas os ponteiros ainda estão lá, porque às vezes as regras precisam ser quebradas. Similarmente, elencos (casts) estão lá para essas vezes que o sistema de digitação precisa ser anulado.
Principais Características de D
Essa seção lista algumas das mais interessantes características de D em varias categorias.Programação Orientada a Objetos
Classes
A natureza orientada a objetos de D vem das classes. O modelo de herança é herança simples aumentada com interfaces. A classe Object é a raíz da hierarquia, então todas as classes implementam um conjunto comum de funcionalidades. Classes são instânciadas por referência, então não é necessário código complexo para limpeza após exceções.Sobrecarga de Operadores
Classes podem ser feitas para trabalharem com operadores existentes para extender o sistema de tipos para suportar tipos novos. Um exemplo seria criar uma classe numerogrante e então sobrecarregar os operadores +, -, * e / para habilitar uso da sintaxe algébrica com eles.Produtividade
Módulos
Arquivos fonte tem uma correspondência um-para-um com módulos. Ao invés de incluir (#include) o texto de um arquivo de declarações, apenas importa um módulo. Não há necessidade de se preocupar com múltiplas importações de um mesmo módulo, nem precisa envolver arquivos de cabeçalho com #ifndef/#endif ou #pragma once, etc.Declaração vs Definição
C++ normalmente requer que funções e classes sejam declaradas duas vezes - a declaração que vai no arquivo de cabeçalho .h, e a definição que vai em um arquivo fonte .c. Isso é um erro propenso e um processo tedioso. Obviamente, os programadores deveriam precisar escrever isso uma vez, e o compilador deveria então extrair a informação de declaração e tornar disponível para importação simbólica. É exatamente assim que D trabalha.Exemplo:
class ABCNão há necessidade de uma definição separada das funções-membro, membros estáticos, externos, nem sintaxe desajeitada como:
{
int func() { return 7; }
static int z = 7;
}
int q;
int ABC::func() { return 7; }Nota: Claro que, em C++, funções triviais como { return 7; } são escritas "em linha" também, mas funções complexas não são. Em adição, se houver qualquer referência dianteira, as funções precisam estar prototipadas. O seguinte não irá trabalhar em C++:
int ABC::z = 7;
extern int q;
class FooMas o código equivalente em D trabalhará:
{
int foo(Bar *c) { return c->bar(); }
};
class Bar
{
public:
int bar() { return 3; }
};
class FooSe uma função em D é inlined (tornada inline) ou não é determinado pelas configurações do otimizador.
{
int foo(Bar c) { return c.bar; }
}
class Bar
{
int bar() { return 3; }
}
Gabaritos
Gabaritos em D oferecem um modo limpo de suportar programação genérica enquanto oferecem o poder da especialização parcial.Arrays associativos
Arrays associativos são arrays com um tipo de dados arbitrário como índice ao invés de ser limitado a índices inteiros. Em essência, arrays associativos são tabelas hash. Arrays associativos tornam rápido, eficiênte, construir tabelas de símbolos livres de bugs.Typedefs Reais
Typedefs em C e C++ são realmente apelidos, como nenhum novo tipo é realmente introduzido. D implementa typedefs reais, onde:typedef int handle;realmente cria um novo tipo handle. Verificação de tipo é obrigatória, e typedefs participam na sobrecarga de funções. Por exemplo:
int foo(int i);
int foo(handle h);
Documentação
Documentação tem sido feita tradicionalmente de duas formas - primeiro há comentários que documentam o que uma função faz, e então isso é reescrito em uma página html separada. E naturalmente, com o passar do tempo, eles tendem a divergir pois o código é atualizado e a documentação separada não. Ser capaz de gerar o requisito documentção diretamente dos comentários embutidos no arquivo fonte não só cortará pela metade o tempo necessário para preparar a documentação, mas será muito mais fácil manter a documentação sincronizada com o código. Ddoc é a especificação para o gerador de documentação de D. Essa página foi gerada pelo Ddoc também.Embora existam ferramentas de terceiros para fazer isso em C++, eles tem muitas falhas sérias:
- É espetacularmente difícel analisar C++ 100% corretamente. Para fazer isso é necessário um compilador C++ completo. Ferramentas de terceiros tendem a analisar somente um subconjunto de C++ corretamente, então seu uso constrangerá o código fonte para aquele subconjunto.
- Compiladores diferentes suportam versões diferentes de C++ e tem extensões diferentes para C++. Ferramentas de terceiros tem um problema combinando todas essa variações.
- Ferramentas de terceiros podem não estar disponíveis para todas as plataformas desejadas, e elas estão necessariamente em um ciclo de atualizações diferente dos compiladores.
- Ter isso nativo do compilador significa que isso é padronizado para todas as implementações de D.Tendo um padrão pronto significa que é mais provavel que de ser usado.
Funções
D tem o suporte esperado para todas as funções ordinárias, incluindo funções globais, funções sobrecarregadas, funções inline, funções-membro, funções virtuais, ponteiros para funções, etc. Além disso:Funções Aninhadas
Funções podem ser aninhadas dentro de outras funções. Isso é altamente útil para fatoração de código, loclização, e técnicas de fechamento de funções.Funções Literais
Funções anonimas podem ser embutidas diretamente em uma expressão.Fechamentos Dinâmicos
Funções aninhadas e funções-membro de classes podem ser referenciadas com fechamentos (também chamados delegados), tornando programação genérica muito mais fácil e segura quanto ao tipo.Parâmetros In, Out, Inout
Especificar isso não somente ajuda a fazer funções mais auto-documentáveis, elimina muito da necessidade de ponteiros sem sacrificar nada, e abre possibilidades para mais ajuda do compilador em encontrar problemas de codificação.Tal torna possível para D interfacear diretamente com uma variedade maior de APIs estrangeiras. Não haveria necessidades de trabalhos paralelos como "Linguagem de Definição de Interfaces".
Arrays
Arrays em C tem várias faltas que podem ser corrigidas:- Informaçãs de dimesão não não é carregada com o array, então deve ser armazenada e passada separadamente. O clássico exemplo disso são os parâmetros de main(int argc, char *argv[]). (Em D, mais é declarado como main(char[][] args).)
- Arrays não são primeiros objetos de classes. Quando um array é passado para uma função, ele é convertido para um ponteiro, embora o confuso protótipo diga que é um array. Quando essa conversão acontece, toda a informação de tipo do array é perdida.
- Arrays em C não podem ser redimensionados. Isso significa que mesmo agregados simples como uma pilha precisam ser construídos como uma complexa classe.
- Arrays em C não tem os limites checados, porque eles não sabem quais os limites do array.
- Arrays são declarados com o [] depois do
identificador. Isso conduz uma sintaxe muito desajeitada para declarar
coisas como um ponteiro para um array:
int (*array)[3];
Em D, o [] para o array vai na esquerda:int[3]* array; // declara um ponteiro para um array de 3 ints
o que é muito mais simples de entender.
long[] func(int x); // declara uma função retornando um array de longs
Strings
Manipulação de strings é tão comum, e tão confusa em C e C++, que é necessário suporte direto na linguagem. Linguagens modernas controlam concatenação de strings, cópia, etc., e assim faz D. Strings são uma consequencia direta do controle melhorado de arrays.Gerenciamento de Recursos
Gerenciamento Automático de Memória
Alocação de memória em D é totalmente com coleta de lixo. Experiência empirica sugere que muitas das complicadas características de C++ são necessárias para administrar desalocação de memória. Com coleta de lixo, a linguagem se torna muito mais simples.Há uma percepção que coleta de lixo é para programadores preguiçosos e principiantes. Eu me lembro quando isso foi dito sobre C++, depois de tudo, não há nada em C++ que não possa ser feito em C, ou em assembly quanto ao assunto.
Coleta de lixo elimina a faixa de código de alocação de memória tediosa e propensa a erros, necessária em C e C++. Isso não significa somente tempo de desenvolvimento muito mais rápido e menores custos de manutenção, mas o programa resultante freqüentemente roda mais rápido!
Claro, coletores de lixo podem ser usados com C++, e eu tenho usado eles em meus próprio projetos em C++. Porém a linguagem não é amigável para coletores, impedindo a efetividade deles. Muitas das bibliotecas de código não podem ser usadas com coletores.
Para discussão mais completa sobre isso, veja coleta de lixo.
Gerenciamento Explícito de Memória
Apesar de D ser uma linguagem com coleta de lixo, as operações new e delete podem ser sobrecarregadas para classes particulares em que um alocador customizado pode ser usado.RAII
RAII é uma moderna técnica de desenvolvimento de software para administrar alocação e desalocação de recursos. D suporta RAII de maneira controlada e previsível que é independente do ciclo de coleta de lixo.Desempenho
Agregados Leves
D suporta estruturas simples no estilo C, para compatibilidade com estruturas de dados em C e porque elas são úteis quando todo poder das classes é desnecessário.Inline Assembler
Device drivers, aplicações de systema de alto desempenho, sistema embutidos, e código especializado algumas vezes precisam imergir em linguagem assembly para ter o trabalho feito. Enquanto implementações de D não são necessárias para implementar o inline assembler, ele é definido como parte da linguagem. A maioria do código assembly necessário pode ser controlado com ele, obviando a necessidade para montadores separados ou DLLs.Muitas implementações de D também suportarão funções intrínsicas análogo ao suporte de C para manipulação de portas de E/S, acesso direto a operações especiais com pontos flutuantes, etc.
Confiança
Uma linguagem moderna deveri fazer todo possível para ajudar o programador a eliminar bugs no código.Ajuda pode vir de muitas formas; de tornar fácil o uso de técnicas mais robustas, de compilar sinalizando código obviamente incorreto, de fazer checagens em tempo de execução.Contratos
Programação de Contrato (inventada por B. Meyer) é uma técnica revolucionária para para ajudar assegurando a "justeza" do programa. A versão de Ddo DBC inclui pré-condições de funções, pós-condições de funções, classes invariantes, e contratos de asserção. Veja Contratos para a implementação de D.Testes de Unidade
Testes de Unidade podem ser adiconados à classes, tal que sejam executados quando o programa for iniciado. Isso ajuda na verificando, em toda construção, que implementações de classes não foram quebradas sem advertência. Os testes de unidade fazem parte do código fonte para uma classe. Criá-los se torna parte natural do processo de desenvolvimento de classes, ao invés de jogar o código terminado na parede para o grupo de testes.Testes de unidade podem ser feitos em outras linguagens, mas o resultado é um pouco confuso e as linguagens não estão se acomodando ao conceito. Teste de unidade é uma característica principal de D. Para funções de biblioteca isso trabalha muito bem, servindo para garantir que as funções realmente trabalhemq para ilustrar como usar as funções.
Considere os muitos códigos de bibliotecas e aplicações em C++ disponíveis para download na web. Quantas delas vem com *quaisquer* testes de verificação, isolando testes de unidade? Menos de 1%? A prática habitual é que se compila, assumimos que trabalha. E queremos saber se as advertências que o compilador cospe no processo são bugs reais ou apenas queixas sobre lêndeas.
Junto com Programação de Contrato, testes de unidade tornam D de longe a melhor linguagem para escrever aplicações robustas seguras. Teste de unidade nos da uma estimativa rápida-e-suja da qualidade de alguns pedaços de código D desconhecidos derrubados em nossos colos - se não há testes de unidade nem contratos, é inaceitável.
Atributos e Instruções de Depuração
Agora depurar é parte da sintaxe da linguagem. O código pode ser habilitado ou desabilitado em tempo de compilação, sem o uso de macros ou comando de pré-precessamento. A sintaxe de depuração habilita um reconhecimento consistente, portável e compreensível que o código fonte precisa ser capaz para gerar compilações de depuração e de lançamento.Captura de Exceções
O modelo superior try-catch-finally é usado ao invé de apenas try-catch. Não há necessidade de criar objetos bobos apenas para ter o destrutor implemente apenas a semântica finally.Sincronização
Programação multithread está ficando mais e mais popular, e D provê primitivas para construir programas multithread. Sincronização pode ser feita a nível de método ou objeto.synchronized int func() { ... }Funções sincronizadas permitem apenas um thread por vez executando a função.
A instrução de sincronização coloca um mutex ao redor do bloco de instruções, controlndo acesso pelo objeto ou global.
Suporte a Técnicas Robustas
- Arrays dinâmicos ao invés de ponteiros
- Variáveis de referência ao invés de ponteiros
- Objetos de referência ao invés de ponteiros
- Coleta de lixa ao invés de adiministação esplícita de memória
- Primitivas nativas para sincronização de threads
- Nenuma macro para inadvertidamente bater código
- Funções inline ao invés de macros
- Imensa redução da necessidade de ponteiros
- Tamanhos de tipos integrais são explícitos
- Sem mais incertezas sobre sinal de chars
- Sem necessidade de declarações duplicadas no em arquivos fonte e cabeçalho.
- Suporte a análise explícita para adiconar código de depuração.
Checagens em tempo de compilação
- Forte checagem de tipo
- Nenhum corpo for vazio
- Atribuições não rendem um resultado booleano
- Condenação de APIs obsoletas
Checagem em tempo de execução
- Expressões assert()
- checagem dos limites do array
- caso indefinido em exceções switch
- exceção fora de memória (out of memory)
- Suporte a Programação de Contrato por classes invariantes, in e out
Compatibilidade
Precedencia de operadores e regras de avaliação
Retém D operadores de C e suas regras de precedência, regras de ordem de avaliação, e regras de promoção. Isso evita bugs sutis que poderiam surgir de ser usado do modo como C faz as coisas que tem uma grande dificuldade de achar bugs devido à diferente semântica.Acesso direto a APIs em C
Não somente D tem tipos de dados que correspondem aos tipos de dados em C, ele prove acesso direto às funções em C. Não há necessidade de escrever funções envolvendo, nem código para copiar membros agregados um a um.Suporte para todos os tipos de dados de C
Tornando possível interfacear com quaisquer APIs C ou bibliotecas existentes. Esse suporte incui estruturas, uniões, enums, ponteiros, e todos os tipos do C99. D incui a capacidade de ajustar o alinhamento de membros de estruturs para assegurar compatibilidade com tipos de dados impostos externamente.Captura de Exceções do SO
O mecanismo de captura de exceções de Dirá se conectar com o modo como o sistema operacional controla exceções em uma aplicação.Uso de Ferramentas Existentes
D produz código em formato de arquivo objeto padrão, possibilitando o uso de montadores padrão, linkers, depuradores, profilers, compressores de executáveis, e outros analisadores, como também se unido com código escrito em outras linguagens.Gerenciamento de Projeto
Versoionando
D provê suporte nativo para geração de múltiplas versões de um programa a partir do mesmo texto. Isso substitui a técnica #if/#endif do pré-processador de C.Condenação
Como código evolui com o tempo, alguns velgos códigos de biblioteca são substituídos por versões novas e melhores. As velhas versões devem estar disponível para suporte a código legado, mas elas podem ser marcadas como condenadas. Código que usa versões condenadas serão normalmente sinalizadas como ilegais, mas seriam permitidos por um interruptod do compilador. Isso tornará fácil para programadores de manutenção identificar quaisquer dependencias de código condenado.Programa de Amostra em D (sieve.d)
/* Números primos do crivo de Eratosthenes */
bool[8191] flags;
int main()
{ int i, count, prime, k, iter;
printf("10 iterations\n");
for (iter = 1; iter <= 10; iter++)
{ count = 0;
flags[] = 1;
for (i = 0; i < flags.length; i++)
{ if (flags[i])
{ prime = i + i + 3;
k = i + prime;
while (k < flags.length)
{
flags[k] = 0;
k += prime;
}
count += 1;
}
}
}
printf ("\n%d primes", count);
return 0;
}