D
Linguagem
Phobos
Comparações

· Visão Geral
· D para Win32
· Win32 DLLs em D
· C .h para Módulos D
· FAQ
· Guia de Estilo
· Exemplo: wc
· Futuro
· D Change Log
· Questões Técnicas
· Razão
· Advertências

Artigos
· Segurança de Exceções
· Gabaritos Revisados

Ferramentas
· Compilador DMD
· Compilador GDC
· Linker
· Profiler
· Code Coverage
· DMD Script Shell
· Depurador Windows

Comunidade
· Novidades
· Fórum
· Anúncios
· Aprenda
· D links

Arquivos
· digitalmars.D
· digitalmars.D.dtl
· digitalmars.D.announce
· digitalmars.D.dwt
· digitalmars.D.learn
· digitalmars.D.bugs
· D.gnu
· Antigo D

Apêndices
· Glossário
· Tabela Ascii
· Reconhecimentos

Razão

Questões sobre as razões de várias decisões de projeto para D que surgem freqüentemente. Isso dirige-se a muitas delas.

Sobrecarga de Operadores

Por que não nomeá-los operator+(), operator*(), etc.?

Esse é o modo como C++ faz isso, e apela para ser capaz de se referir a sobrecarregar '+' com 'operator+'. O problema é que as coisas não se ajustam totalmente. Por exemplo, há os operadores de comparação <, <=, >, e >=. Em C++, os quatro devem ser sobrecarregados para ter a cobertura completa. Em D, somente uma função cmp() deve ser definida, e os operadores de comparação são derivados dela pela análise semântica.

Sobrecarregar operator/() também não provê nenhum modo sométrico, como uma função membro, para sobrecarregar a operação reversa. Por exemplo,

class A
{
int operator/(int i); // sobrecarrega (a+i)
static operator/(int i, A a) // sobrecarrega (i+a)
}
A segunda sobrecarga faz a sobrecarga reversa, mas ela não pode ser virtual, assim tem uma assimetria confusa com a primeira sobrecarga.

Por que não permitir funções de sobrecarga de operadores definida globalmente?

  1. Sobrecarga de operadores pode ser feita somente com um argumento como um objeto, então elas logicamente pertencem como funções membro daquele objeto. Isso deixa o caso do que fazer quando os operandos são objetos de tipos diferentes:
  2. class A { }
    class B { }
    int add(class A, class B);
    Deveria add() estar na classe A ou B? A solução estilistica óbvia seria colocá-la na classe do primeiro operando,
    class A
    {
    int add(class B) { }
    }
  3. Sobrecarga de operadores normalmente precisa acessar membros privados da classe, e fazê-as globais quebra o encapsulamento orientado a objetos de uma classe.
  4. (2) pode ser endereçado pela sobrecarga de operador automaticamente ganhando acesso "friend", mas tal comportamento incomum está em conflito com D, que é simples.

Por que não permitir operadores definidos pelo usuário?

Estes podem ser muito úteis para adicionar novas operações infixas para vários símbolos unicode. O problema é que em D, os tokens são supostos como sendo completamente independentes da análise semântica. Operadores definidos pelo usuário poderiam quebrar isso.

Por que não permitir precedência de operadores definida pelo usuário?

O problema é que isso afeta a análise sintática, e a análise sintática é suposta como sendo completamente independente da análise semântica em D.

Por que não usar nomes de operadores como __add__ and __div__ ao invés de add, div, etc.?

Palavras-chave com __ deveriam indicar uma extensão proprietária da linguagem, não uma parte básica da linguagem.

Por que não ter sobrecarga de operadores binários sendo membros estáticos, assim ambos os argumentos são especificados, e não há qualquer questão sobre a operação reversa?

Isso significa que sobrecarga de operador não pode ser virtual, e então provavelmente seria implementada como uma concha ao redor de outra função virtual para fazer o trabalho real. Isso ventará parecendo um entalhe feio. Secundariamente, a função cmp() já é uma sobrecarga de operador definida em Object, ela precisa ser virtual por várias razões, e torná-la assimetrica com outras sobrecargas de operador faz confusão desnecesária.

Propriedades

Por que D tem propriedades como T.infinity na linguagem núcleo para dar o infinito de um tipo de ponto flutuante, ao invés de fazer isso em uma biblioteca como em C++:  std::numeric_limits::infinity ?

Vamos refomular a frase como "se há um modo de expressar isso na linguagem existente, por que embutir isso na linguagem núcleo?" A respeito de T.infinity:
  1. Construir isso na linguagem núcleo significa que a linguagem núcleo sabe o que um infinito de ponto flutuante é. Sendo feito em camadas com gabaritos, typedefs, moldes, padrões de bit constante, etc., ela não sabe o que isso é, e é imporvável dar mensagens de erros sensatas se abusado.
  2. Um efeito colateral de (1) é ser improvável de ser capaz de usar isso efetivamente em dobramentos constantes e outras otimizações.
  3. Instanciar gabaritos, carregar arquivos #include, etc., custa tempo de compilação e memória.
  4. O pior, entretanto, é que comprimentos só chegarão a infinito, implicando "a linguagem e compilador não sabem nada sobre ponto flutuante IEEE 754 - então não pode ser confiável." E de fato muitos excelentes compiladores C++ não controlam NaN's corretamente em comparações de pontos flutuantes. (Digital Mars C++ faz isso corretamente.) C++98 não diz nada sobre controle de NaN ou Infinito em expressões ou funções de biblioteca. Então deve ser assumido que não trabalha.
Resumindo, há muito mais para suportar NaNs e infinitos que ter um gabarito que retorna um bit padrão. Isso deve ser nativo à lógica nativa do compilador, e deve penetrar todo código de biblioteca que se trata de ponto flutuante. E isso deve estar no Padrão. Para ilustrar, se op1 ou op2 ou ambos são NaN, então:
(op1 < op2)
não rende o mesmo resultado que:
!(op1 >= op2)
se os NaNs são feitos corretamente.

Por que usar static if(0) ao invés de if (0)?

Algumas limitações são:
  1. if (0) introduz um novo escopo, static if(...) não. Por que isso importa? Isso importa se alguém quer declarar condicionalmente uma nova variável:
    static if(...) int x;
    else long x;
    x = 3;
    considerando que:
    if(...) int x; else long x;
    x = 3; // erro, x não definido
  2. Condições falsas de static if não devem trabalhar semanticamente. Por exemplo, pode depender de uma declaração compilada condicionalmente em algum outro lugar:
    static if(...) int x;
    int test()
    {
    static if(...) return x;
    else return 0;
    }
  3. Static if's podem aparecer onde somente declarações são permitidas:
    class Foo
    {
    static if(...)
    int x;
    }
  4. Static if's podem declarar novos tipos apelido:
    static if(0 || is(int T)) T x;