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

Advertências

Dependendo do ponto de vista, advertências são ou um sintoma de projeto de linguagem quebrado ou um 'fiapo' útil como ferramenta para analisar código e procurar por manchas de dificuldade potencial. A maioria do tempo, essas manchas de dificuldade serão código legítimo planejado para ser daquele jeito. Mais raramente, pode indicar um erro não-intencional por parte do programador.

Advertências não são uma parte definida da Linguagem de Programação D. Elas existem à arbítrio do vendedor do compilador, e provavelmente variará de vendedor para vendedor. Todas as construções que uma implementação pode gerar uma mensagem de advertência são código D legal.

Estas são as advertyências geradas pelo compilador D da Digital Mars quando a interruptor -w é lançado. A maioria tem gerado o mesmo debate animado sobre se deveria ser uma advertência, um erro, e qual seria o jeito correto de escrever código D nessas situações. Já que nenhum consenso emergiu, elas aparecem como advertências opcionais, com alternativas de como escrever código correto.

warning - implicit conversion of expression expr of type type to type can cause loss of data

D segue as regras de C e C++ relativas a promoção integral padrçao em expressões. Isso é feito por razões de compatibilidade e porque CPUs modernas são projetadas para executar tal semântica eficientmente. Essas regras também  incluem regas de estreitamente implicito, onde o resultado de tal pode ser moldado devolta em um tipo menor, talvez perdendo bits significantes no processo:
byte a, b, c;
...
a = b + c;
b e c são ambos promovidos para o tipo int usando as regras de promoção integral padões. O resultado da soma então também é um int. Para ser atribuído para a, aquele int é implicitamente convertido para um byte.

Se é um bug ou não em um programa depende se os valores para b e c podem possivelmente causar um tranbordamento, e se esse transbordamento importa ou não para o algorítmo. A advertência pode ser resolvida por:

  1. Inserir um molde:
    a = cast(byte)(b + c);
    Isso elimina a advertência, mas já que moldar é um instrumento obtuso que evita checagem de tipo, isso pode mascarar outro bug que poderia ser introduzido se os tipos de a, b ou c mudarem no futuro, ou se seus tipos são ajustados por uma instanciação de gabarito. (Em código genérico, o cast(byte) provavelmente seria cast(typeof(a))).
  2. Mudar o tipo de a para int. Isso é geralmente uma solução melhor, mas claro que pode não trabalhar se isso deve ser de um tipo menor, que nos leva a:
  3. Fazer uma checagem por transbordamento em tempo de execução:
    byte a, b, c;
    int tmp;
    ...
    tmp = b + c;
    assert(cast(byte)tmp == tmp);
    a = cast(byte)tmp;
    Isso assegura que nenhum bit significante será perdido.
Algumas soluções de linguagem propostas são:
  1. Ter o compilador automaticamente inserindo o euquivalente da opção 3 checagem em tempo de execução.
  2. Adicionar uma nova construção, implicit_cast(tipo)expressão que é uma forma restrita do molde geral, e somente trabalhará onde moldes implicitos normalmente seriam permitidos.
  3. Implementar o implicit_cast como um gabarito.

warning - array 'length' hides other 'length' name in outer scope

Dentro do [ ] de uma expressão de indexação ou fatia de array, a variável length é definida e ajustada para ser ter o comprimento daquele array. O escopo de length é do '[' de abertura até o ']' de fechamento.

Se length foi declarado como um nome de variável em um escopo exterior, aquela versão pode ter sido planejada para uso entre o [ ]. Por exemplo:

char[10] a;
int length = 4;
...
return a[length - 1]; // retorna a[9], não a[3]
A advertêcnia pode ser resolvida com:
  1. Renomear o length exterior para outro nome.
  2. Substituir o uso de length dentro do [ ] com a.length.
  3. Se length estão em ecopo global ou de clase, e isso era o que a pessoa pretendia para ser usado, use .length ou this.length para desambiguação.
Algumas soluções de linguagem propostas são:
  1. Faça length um símbolo especial ou uma pavavra reservada ao invés de uma variável declarada implicitamente.

warning - no return at end of function

Considere o seguinte:
int foo(int k, Collection c)
{
foreach (int x; c)
{
if (x == k)
return x + 1;
}
}
e assuma que a natureza do algorítmo é que x sempre será encontrado em c, então o foreach nunca caia para baixo do código. Não há return no fim da função, pois aquele ponto não é alcançável e qualquer instrução de retorno seria código morto. Isso é perfeitamente código legítimo. O compilador D, para ajudar a assegurar a robustez de tal código, assegurará que é correto inserindo automaticamente uma instrução assert(0); no fim da função. Então, se há um erro na suposição que o foreach nunca cairá, ele será pego em tempo de execuçãocom uma óbvia falha de asserção, que é melhor que o código apenas cair do fim causando falhas irregulares e arbitrárias.

O comportamento de D nisso, porém, não é comum para outras linguagens, e alguns programadores serã intensamente incomodados com confiar nisso, ou eles desejam ver o erro em tempo de compilação ao invés de em tempo de execução. Eles desejam ver algo explicito espressado no código fonte que o foreach não pode cair. Conseqüentemente a advertência.

A advertência pode ser resolvida por:

  1. Colocando uma instruão de retorno no fechamento da função, retornando algum valor arbitrário (depois de tudo, ele nunca será executado):
    int foo(int k, Collection c)
    {
    foreach (int x; c)
    {
    if(x == k)
    return x + 1;
    }
    return 0; // suprime advertência sobre nenhuma instrução de retorno
    }
    Enquanto fazer isso é surpreendentemente comum, e acontece quando o programador é inexperiente ou está com pressa, é um solução espetacularmente ruim. O problema acontece quando o foreach cai devido a um bug, então ao invés de o bug ser detectado, a função retorna um valor inexperado, que pode causar outros problemas ou seguir não detectado. Há outra questão com o programador de manutenção que vê isso, e ao analisar o comportamento do código, deseja saber por que há uma instrução de retorno que nunca será executada. (Isso pode ser resolvido com comentários, mas comentários são sempre perdidos, desatualizados, ou simplesmente errados.) Código morto é sempre um problema confuso para programação de manutenção, então inserir isso deliberadamente é uma má idéia.
  2. Uma solução melhor é tornar explícito o que a linguagem D faz implicitamente - por um assert lá:
    int foo(int k, Collection c)
    {
    foreach (int x; c)
    {
    if (x == k)
    return x + 1;
    }
    assert(0);
    }
    Agora, se o foreach cair, o erro será detectado. Além disso, ele é auto-documentado.
  3. Outra alternativa é fazer um throw com uma classe de erro customizada e uma mensagem mais amiável:
    int foo(int k, Collection c)
    {
    foreach (int x; c)
    {
    if (x == k)
    return x + 1;
    }
    throw new MyErrorClass("caiu do fim de foo()");
    }

warning - switch statement has no default

Similar à advertência de sem retorno é o sem padrão em uma advertência de switch. Considere:
switch (i)
{
case 1: dothis(); break;
case 2: dothat(); break;
}
De acordo com a semântica da linguagem D, isso significa que os únicos valores possíveis para i são 1 e 2. Quaisquer outros valores representam um bug no programa. Para detectar esse erro, o compilador implementa o switch como se fosse escrito:
switch (i)
{
case 1: dothis(); break;
case 2: dothat(); break;
default: throw new SwitchError();
}
Isso é bem diferente do comportamento em C e C++, que é como se o switch fosse escrito:
switch (i)
{
case 1: dothis(); break;
case 2: dothat(); break;
default: break;
}
O potencial para bugs com isso é alto, como é um erro comum acidentalmente omitir um caso, ou adicionar um novo valor em uma parte do programa e deixar de adicionar um caso para ele em outra parte. Embora D capture esse erro em tempo de execução, alguns preferem ao menos uma advertência então tais erros podem ser capturados em tempo de compilação.

A advertência pode ser resolvida por:

  1. Inserir um default explícito na forma:
    switch (i)
    {
    case 1: dothis(); break;
    case 2: dothat(); break;
    default: assert(0);
    }
  2. Como no retorno perdido, um default com um throw de uma classe de erro customizada pode ser usado.

warning - statement is not reachable

Considere o seguinte código:
int foo(int i)
{
return i;
return i + 1;
}
A segunda instrução return não é alcançável, isto é, é código morto. Enquanto código morto é estilo pobre em código de lançamento, pode ocorrer legitimamente quando tentar isolar um bug ou experimento com diferentes pedaços de código. A advertência pode ser resolvida com:
  1. Comente o código morto com comentários /+ ... +/:
    int foo(int i)
    {
    return i;
    /+
    retorna i + 1;
    +/

    }
  2. Ponha o código morto dentro de um version(none) condicional:
    int foo(int i)
    {
    return i;
    version (none)
    {
    return i + 1;
    }
    }
  3. Somente compile com advertências ligadas quando fazendo construções de lançamento.