As constantes de um caractere são melhores que as literais?

127

Recentemente, encontrei uma classe que fornece praticamente todos os caracteres como uma constante; tudo de COMMApara BRACKET_OPEN. Pensando se isso era necessário; Eu li um "artigo" que sugere que pode ser útil extrair literais de caractere único em constantes. Então, eu sou cético.

O principal atrativo do uso de constantes é que elas minimizam a manutenção quando uma mudança é necessária. Mas quando vamos começar a usar um símbolo diferente de ',' para representar uma vírgula?

A única razão que vejo para usar constantes em vez de literais é tornar o código mais legível. Mas é city + CharacterClass.COMMA + state(por exemplo) realmente mais legível do que city + ',' + state?

Para mim, os contras superam os profissionais, principalmente porque você introduz outra classe e outra importação. E acredito em menos código sempre que possível. Então, eu estou querendo saber qual é o consenso geral aqui.

Dia de Austin
fonte
33
Hmm ... pode ser útil para diferentes localidades, talvez? Por exemplo, alguns idiomas usam guillements (aspas angulares «e ») como aspas, em vez do padrão do inglês "(ou aparência mais agradável e ). Além disso, parece apenas um conjunto de personagens mágicos. Supondo duas instâncias de CharacterClasschamado englishCharse frenchChars, é possível que englishChars.LEFT_QUOTEseja , enquanto frenchChars.LEFT_QUOTEpode ser «.
Justin Time
4
Existem muitas variantes diferentes nas vírgulas: en.wikipedia.org/wiki/Comma#Comma_variants - talvez essa não seja uma idéia tão estúpida, especialmente se o seu código-fonte puder ser codificado como utf-8.
Aaron Hall
21
No seu caso, é como chamar uma variável "número". Sua constante deveria ter sido chamada DELIMITER. Ou deve ser CITY_STATE = "{0}, {1}"
the_lotus 07/07
13
Esse artigo que você vinculou é muito terrível. As constantes nunca devem ser jogadas em um balde como esse. Coloque-os nas classes em que eles têm contexto: em essência, a classe com a constante fornece o contexto em que a constante é usada. Por exemplo, Java File.separator. A classe informa o tipo de separador. Ter uma classe nomeada Constsou Constantsnão fornecer contexto e dificulta o uso correto das constantes.

Respostas:

183

Tautologia :

É muito claro que, se você ler a primeira frase da pergunta, não se trata de usos apropriados, como eliminar números mágicos , mas de uma consistência tola, terrível e irracional, na melhor das hipóteses. Qual é o que esta resposta aborda

O senso comum diz-lhe que const char UPPER_CASE_A = 'A';ou const char A = 'A'não acrescenta nada, mas manutenção e complexidade ao seu sistema. const char STATUS_CODE.ARRIVED = 'A'é um caso diferente.

As constantes devem representar coisas imutáveis ​​em tempo de execução, mas podem precisar ser modificadas no futuro em tempo de compilação. Quando seria const char A =igual a algo diferente A?

Se você public static final char COLON = ':'vir o código Java, encontre quem escreveu isso e quebre seus teclados. Se a representação COLONmudar para sempre, :você terá um pesadelo de manutenção.

Ofuscação:

O que acontece quando alguém muda para, COLON = '-'porque onde eles estão usando ele precisa de um -lugar em todo lugar? Você vai escrever testes de unidade que dizem basicamente assertThat(':' == COLON)para cada constreferência para garantir que não sejam alterados? Apenas para alguém corrigir o teste quando eles mudam?

Se alguém realmente argumenta que public static final String EMPTY_STRING = "";é útil e benéfico, você apenas qualificou seus conhecimentos e os ignorou com segurança em todo o resto.

Ter todos os caracteres imprimíveis disponíveis com uma versão nomeada apenas demonstra que quem o fez não está qualificado para escrever código sem supervisão.

Coesão:

Também reduz artificialmente a coesão, porque afasta as coisas das que as usam e estão relacionadas a elas.

Na programação de computadores, coesão refere-se ao grau em que os elementos de um módulo pertencem um ao outro. Assim, a coesão mede a força do relacionamento entre partes da funcionalidade dentro de um determinado módulo. Por exemplo, em sistemas altamente coesos, a funcionalidade está fortemente relacionada.

Acoplamento:

Ele também reúne muitas classes não relacionadas, porque todas acabam referenciando arquivos que não estão realmente relacionados ao que fazem.

Acoplamento apertado ocorre quando um grupo de classes é altamente dependente um do outro. Esse cenário surge quando uma classe assume muitas responsabilidades ou quando uma preocupação é espalhada por muitas classes em vez de ter sua própria classe.

Se você usasse um nome melhor como DELIMITER = ','você ainda teria o mesmo problema, porque o nome é genérico e não possui semântica. A reatribuição do valor não ajuda mais a fazer uma análise de impacto do que procurar e substituir o literal ','. Porque o que é que algum código usa e precisa de ,outros códigos, mas precisa ;agora? Ainda tem que olhar para cada uso manualmente e alterá-los.

Na natureza:

Recentemente refatorei um 1,000,000+ LOCaplicativo com 18 anos de idade. Tinha coisas assim public static final COMMA = SPACE + "," + SPACE;. Isso não é nada melhor do que apenas indicar " , "onde é necessário.

Se você quiser discutir a legibilidade, precisa aprender a configurar seu IDE para exibir whitespacecaracteres onde possa vê-los ou o que quer que seja, esse é apenas um motivo extremamente preguiçoso para introduzir entropia em um sistema.

Ele também havia ,definido várias vezes com vários erros de ortografia da palavra COMMAem vários pacotes e classes. Com referências a todas as variações misturadas no código. Não era nada menos que um pesadelo tentar consertar algo sem quebrar algo completamente não relacionado.

Mesmo com o alfabeto, havia múltiplos UPPER_CASE_A, A, UPPER_A, A_UPPERque na maioria das vezes eram iguais A , mas em alguns casos não foram . Para quase todos os personagens, mas nem todos os personagens.

E a partir das histórias de edição, não parecia que uma única delas fosse editada ou alterada ao longo dos 18 anos, por causa do que agora deveria ser uma razão óbvia, seria que ela quebraria muitas coisas que não eram rastreáveis, assim você tem uma nova variável nomes apontando para a mesma coisa que nunca pode ser alterada pelo mesmo motivo.

Em nenhuma realidade sadia você pode argumentar que esta prática não está fazendo nada, mas começando na entropia máxima.

Refatorei toda essa bagunça e delineei todas as tautologias e as novas contratações da faculdade eram muito mais produtivas porque não precisavam caçar através de vários níveis de indireção o que essas constreferências realmente apontavam, porque não eram confiáveis ​​no que eram chamadas vs o que eles continham.


fonte
112
Talvez você deva adicionar um contra-exemplo: const char DELIMITER = ':'seria realmente útil.
Bergi 06/07/19
115
Eu faria vários argumentos que EMPTY_STRINGsão benéficos. (1) É muito mais fácil encontrar todos os usos de EMPTY_STRINGem um arquivo do que encontrar todos os usos de "". (2) quando vejo, EMPTY_STRINGtenho certeza absoluta de que o desenvolvedor pretendia que essa sequência estivesse vazia e que não é uma edição incorreta ou um espaço reservado para que uma sequência seja fornecida posteriormente. Agora, você alega que, ao fazer esse argumento, você pode qualificar meu conhecimento e me ignora com segurança para sempre. Então, como você qualifica meu conhecimento? E você planeja ignorar meus conselhos para sempre? Eu não tenho nenhum problema de qualquer maneira.
Eric Lippert
39
@immibis: Podemos parar de pensar nessas coisas como úteis no contexto de gerenciamento de mudanças. Eles são constantes. Eles não mudam. Pense nelas como útil no contexto dos humanos que pesquisam e compreendem a semântica do código . Saber que algo é um delimitador de par de valores-chave é muito mais útil do que saber que é um ponto e vírgula; isso é um fato sobre o domínio semântico da preocupação do programa, não sua sintaxe .
Eric Lippert
15
@EricLippert: Estou vendo o ponto de outras pessoas aqui que apontam que a única garantia que a constfornece é que ela não será alterada no tempo de execução (após a compilação), embora eu concorde com você que o significado semântico de consté muito mais importante do que seu uso como uma ferramenta de gerenciamento de mudanças. Dito isto, certamente posso imaginar um const EARLIEST_OS_SUPPORTEDque não seja apenas semanticamente consistente, mas também mudará ao longo do tempo à medida que o programa evolui e o antigo lixo é removido.
Robert Harvey
16
@ DanielJour: Então este é um terceiro argumento para EMPTY_STRING; que um IDE bem projetado mostrará ferramentas que me permitem tratar esta entidade simbolicamente, em vez de sintaticamente. Generalize isso para um quarto argumento: que a biblioteca de ferramentas de análise de código que fica abaixo do IDE pode permitir a análise programática avançada da correção do código no nível simbólico . Um desenvolvedor que deseja tirar proveito das ferramentas mais avançadas do que aquelas escritas há 40 anos, precisa fazer apenas pequenas mudanças em seus hábitos para colher os frutos das ferramentas avançadas.
Eric Lippert 07/07
145

O principal atrativo do uso de constantes é que elas minimizam a manutenção quando uma mudança é necessária.

ABSOLUTAMENTE NÃO. Esse não é o motivo para usar constantes, porque as constantes não mudam por definição . Se uma constante sempre muda , não era uma constante, era?

O apelo do uso de constantes não tem nada a ver com gerenciamento de alterações e tudo a ver com tornar os programas passíveis de serem escritos, compreendidos e mantidos pelas pessoas . Se eu quiser saber em todos os lugares do meu programa onde dois pontos são usados ​​como um separador de URL, eu posso saber isso muito facilmente se tiver a disciplina para definir um URLSeparator constante e não puder saber tão facilmente se tiver que esperar por :e obtenha todos os locais do código onde :é usado para indicar uma classe base, ou um ?:operador, ou qualquer outra coisa.

Discordo completamente das outras respostas que afirmam que isso é uma perda de tempo inútil. As constantes nomeadas acrescentam significado a um programa e essas semânticas podem ser usadas por humanos e máquinas para entender um programa mais profundamente e mantê-lo com mais eficiência.

O truque aqui não é evitar constantes, mas nomeá-las com suas propriedades semânticas em vez de suas propriedades sintáticas . Para que a constante está sendo usada? Não ligue a Commamenos que o domínio comercial do seu programa seja tipografia, análise de idioma inglês ou algo semelhante. Pode chamá-lo ListSeparatorou algo assim, para tornar clara a semântica.

Eric Lippert
fonte
42
Embora eu concorde com o espírito do que você está dizendo aqui, sua segunda / terceira frase não está realmente correta. Uma constante pode mudar entre as versões de um arquivo. De fato, a maioria dos programas que eu escrevo tem uma constante chamada algo como MY_VER, que contém o número da versão atual do programa, que pode ser usada durante todo o restante do programa, em vez de uma string mágica como "5.03.427.0038". O benefício adicional é que você diz que forneceu informações semânticas.
Monty Mais difícil
50
Para ser justo, o ponto de uma constante é que ela não muda durante o tempo de execução após a inicialização, não que não mude entre compilações. Da perspectiva de um compilador, o ponto é que o compilador pode fazer suposições de que o programa não pode modificá-lo; se o programador tem permissão para modificá-lo quando recompilar não altera sua constante. Também pode haver casos em que o software obtém um valor somente leitura do hardware, talvez desreferenciando um const volatile T*ponteiro para um endereço predeterminado; enquanto o programa não pode alterá-lo, o hardware pode.
Justin Time
6
@ MontyHarder: Bom ponto. Minha opinião é informada pelo fato de que normalmente uso linguagens que distinguem entre constantes - que devem ser eternamente imutáveis ​​- e variáveis ​​que podem ser atribuídas uma vez - que podem mudar de versão para versão, executar para executar ou qualquer outra coisa. Uma constante e uma variável são coisas diferentes; um permanece o mesmo e o outro varia com o tempo.
Eric Lippert
7
@SteveCox: eu concordo; a maneira como o C / C ++ caracteriza "const" é estranha e de uso limitado. A propriedade que desejo das constantes é que seus valores não mudam, não que eu seja impedido de alterá-los em algumas funções, mas não em outras.
Eric Lippert
15
"Este não é o motivo para usar constantes, porque as constantes não mudam por definição. Se uma constante sempre muda, não era uma constante, era?" Alterar constantes no tempo de compilação (obviamente não no tempo de execução) é perfeitamente normal. É por isso que você fez deles uma "coisa" claramente rotulada em primeiro lugar. Obviamente, as constantes do OP são lixo, mas pense em algo como const VERSION='3.1.2'ou const KEYSIZE=1024ou o que for.
AnoE
61

Não, isso é idiota.

O que não é necessariamente idiota é colocar coisas assim em rótulos nomeados por razões de localização. Por exemplo, o delimitador de milhares é uma vírgula na América (1.000.000), mas não é uma vírgula em outros locais. Colocar isso em um rótulo nomeado (com um nome apropriado, sem vírgula) permite ao programador ignorar / abstrair esses detalhes.

Mas fazer uma constante porque "cordas mágicas são ruins" é apenas um cultivo de carga.

Telastyn
fonte
8
A localização é geralmente mais complicada do que apenas constantes de string. Por exemplo, alguns idiomas desejam delimitador de lista entre todos os itens da lista, enquanto outros excluem o delimitador antes do último item. Portanto, geralmente não é necessário constantes localizadas, mas regras localizadas .
Vlad
19
Na verdade, o delimitador de milhares não é necessariamente um delimitador de milhares em outros locais (China / Japão). Nem é definido após um número constante de dígitos (Índia). Ah, e pode haver delimitadores diferentes, dependendo se é um delimitador 1000 ou o delimitador 1000000 (México). Mas isso é menos problemático do que não usar os dígitos ASCII de 0 a 9 em alguns locais (farsi). ux.stackexchange.com/questions/23667/...
Peter
11
A localização do @Vlad é muito mais complexa do que isso, no entanto, o separador de milhares é um exemplo bem conhecido que as pessoas reconhecem.
Depende da estratégia de localização ... você altera todas as constantes no seu programa para traduzi-lo? Ou você deveria ler os valores de um arquivo (ou outro repositório de dados), tornando-os efetivamente variáveis ​​de tempo de execução?
Paŭlo Ebermann
Isso não seria útil como uma constante, então. O programa precisaria ser recompilado para localidades, o que é uma prática terrível. Eles devem ser variáveis ​​carregadas dos arquivos de definição e pesquisadas conforme necessário. Não que eu discorde do ponto (votei a resposta para cima), mas tomaria uma posição mais difícil sobre o assunto.
29

Existem alguns caracteres que podem ser ambíguos ou usados ​​para vários propósitos diferentes. Por exemplo, usamos '-'como hífen, sinal de menos ou até mesmo um hífen. Você pode criar nomes separados como:

static const wchar_t HYPHEN = '-';
static const wchar_t MINUS = '-';
static const wchar_t EM_DASH = '-';

Posteriormente, você pode optar por modificar seu código para desambiguar, redefinindo-o como:

static const wchar_t HYPHEN = '-';
static const wchar_t MINUS = '\u2122';
static const wchar_t EM_DASH = '\u2014';

Essa pode ser uma razão pela qual você consideraria definir constantes para determinados caracteres únicos. No entanto , o número de caracteres ambíguos dessa maneira é pequeno. No máximo, parece que você faria isso apenas para aqueles. Eu também argumentaria que você poderia esperar até realmente precisar distinguir os caracteres ambíguos antes de fatorar o código dessa maneira.

Como as convenções tipográficas podem variar de acordo com o idioma e a região, é melhor você carregar essa pontuação ambígua em uma tabela de tradução.

Adrian McCarthy
fonte
Para mim, esta é a única razão válida para criar constantes de caracteres
FP
2
Usar -como traço em é bastante enganador ... é muito curto para isso na maioria das fontes. (É ainda mais curto do que um traço.)
Paulo Ebermann
OK, não é o melhor exemplo. Comecei com strings e wchar_tes e usei a convenção padrão de manuscritos "--"para o traço. Mas o exemplo original estava usando caracteres únicos, então mudei para permanecer fiel à pergunta. Existem pessoas que digitam -traços, especialmente quando trabalham em uma fonte de tom fixo.
Adrian McCarthy
11
@ PaŭloEbermann Não, tradicionalmente um traço eme é a largura do caractere 'm' de um tipo de letra e um traço é a largura de um caractere 'n'.
Dizzley
@ Dizzley sim, e hífen-largura <n-largura <m-largura.
Pa Elo Ebermann
22

Uma constante deve adicionar significado.

Definir COMMA como vírgula não adiciona significado, porque sabemos que uma vírgula é uma vírgula. Em vez disso, destruímos o significado, porque agora a COMMA pode não ser mais uma vírgula.

Se você usar uma vírgula para uma finalidade e quiser usar uma constante nomeada, nomeie-a após sua finalidade. Exemplo:

  • city + CharacterClass.COMMA + state = ruim
  • city + CITY_STATE_DELIMITER + state = bom

Use funções para formatar

Pessoalmente, prefiro FormatCityState(city, state)e não me importo com a aparência do corpo dessa função, contanto que seja curto e passe nos casos de teste.

Peter
fonte
11
Ah, mas uma vírgula nem sempre é a mesma vírgula. Eu poderia definir COMMA = '\ u0559' ou '\ u060C' etc. (consulte Unicode) ou até transformá-lo em uma variável posteriormente e lê-lo em um arquivo de configuração. Dessa forma, ele ainda terá o mesmo significado , mas apenas um valor diferente. Que tal isso.
Sr. Lister
2
@MrLister: YAGNI. Se você tem essa necessidade: ótimo! Você tem uma boa solução. Mas se você não o fizer, não bagunce seu código, porque talvez um dia você possa. Além disso, na minha experiência, se você tentar introduzir abstrações sem função na sua base de código, as pessoas não são boas em ser consistentes. Portanto, mesmo que você tenha definido o COMMA com a intenção de usar outro código, em um programa de tamanho e idade suficientes para que a escolha seja importante, é provável que você descubra que a constante não foi usada em qualquer lugar que deveria ter. sido (e vice-versa, pode ter sido usado de forma inadequada também).
Eamon Nerbonne
17

A ideia de que uma constante COMMA é melhor ','ou ","mais fácil de desmascarar. Certamente, há casos em que faz sentido, por exemplo, final String QUOTE = "\"";economizar muito na legibilidade sem todas as barras, mas barrar caracteres de controle de idioma como \ 'e "eu não os achei muito úteis.

Usar final String COMMA = ","não é apenas uma forma ruim, é perigoso! Quando alguém deseja alterar o separador de ","para ";", pode alterar o arquivo de constantes para, COMMA = ";"porque é mais rápido fazer isso e simplesmente funciona. Exceto, você sabe, todas as outras coisas que usavam o COMMA agora também são ponto-e-vírgula, incluindo coisas enviadas a consumidores externos. Portanto, ele passa em todos os seus testes (porque todo o código de organização e não-organização também estava usando COMMA), mas os testes externos falharão.

O que é útil é dar nomes úteis. E sim, às vezes várias constantes terão o mesmo conteúdo, mas nomes diferentes. Por exemplo final String LIST_SEPARATOR = ",".

Portanto, sua pergunta é "são constantes de caracteres únicos melhores que literais" e a resposta é inequivocamente não, elas não são. Mas ainda melhor do que os dois, é um nome de variável com escopo limitado que diz explicitamente qual é o seu objetivo. Claro, você gastará alguns bytes extras nessas referências extras (supondo que eles não sejam compilados, o que provavelmente serão), mas em manutenção a longo prazo, que é onde está o maior custo do aplicativo, eles valem a pena fazer.

corsiKa
fonte
Que tal definir DISP_APOSTROPHE condicionalmente como um caractere de aspas simples à direita ASCII 0x27 ou Unicode (que é uma versão mais tipograficamente apropriada de um apóstrofo), dependendo da plataforma de destino?
Supercat
3
Na verdade, o QUOTEexemplo prova que também é uma má ideia, pois você a atribui ao que geralmente é conhecido popularmente como DOUBLE QUOTEe QUOTEimplica o SINGLE_QUOTEque é mais corretamente referido como APOSTROPHE.
3
@JarrodRoberson Eu não acho que a cotação implique aspas simples, pessoalmente - mas essa é outra boa razão para remover a ambiguidade onde você pode!
corsiKa
2
Não gosto do QUOTEexemplo por um motivo adicional - isso torna as seqüências de leitura construídas com ele ainda mais difíceis. "Hello, my name is " + QUOTE + "My Name" + QUOTEEste é um exemplo trivial e ainda parece ruim. Ah, claro, em vez de concatenação, você pode usar tokens de substituição também "Hello, my name is %sMy Name%s".format(QUOTE, QUOTE)pode ser pior. Mas, ei, vamos tentar tokens indexados "Hello, my name is {0}My Name{0}".format(QUOTE)ugh, não muito melhor. Qualquer string não trivial gerada com aspas seria ainda pior.
VLAZ
2
@corsiKa - Vou viver com as aspas reais que escaparam. Se eu não conseguir escapar de um, o IDE que eu uso reclamará imediatamente. O código provavelmente também não será compilado. É bastante fácil de detectar. Quão fácil é cometer um erro ao fazê-lo. "My name is" + QUOTE + "My Name" + QUOTEEu realmente cometi o mesmo erro três vezes ao escrever o comentário acima. Você consegue identificar? Se você leva um pouco, é o espaço que faltava depois é . Você formata a string? Nesse caso, uma sequência com vários tokens para substituir será ainda pior. Como devo usá-lo para que fique mais legível?
VLAZ
3

Eu trabalhei escrevendo lexers e analisadores e usei constantes inteiras para representar terminais. Os terminais de um caractere passaram a ter o código ASCII como seu valor numérico por uma questão de simplicidade, mas o código poderia ter sido algo totalmente diferente. Então, eu teria um T_COMMA ao qual foi atribuído o código ASCII para ',' como seu valor constante. No entanto, também havia constantes para os não terminais que foram designados números inteiros acima do conjunto ASCII. Olhando para geradores de analisadores, como yacc ou bison, ou analisadores escritos usando essas ferramentas, tive a impressão de que é basicamente como todo mundo fazia isso.

Portanto, enquanto, como todo mundo, acho inútil definir constantes com o propósito expresso de usar as constantes em vez dos literais em todo o seu código, acho que existem casos extremos (analisadores, digamos) em que você pode encontrar código repleto de constantes como você descreve. Observe que, no caso do analisador, as constantes não estão lá apenas para representar literais de caracteres; eles representam entidades que só poderia acontecer a ser literais de caracteres.

Posso pensar em mais alguns casos isolados em que pode fazer sentido usar constantes em vez dos literais correspondentes. Por exemplo, você pode definir NEWLINE como o literal '\ n' em uma caixa unix, mas '\ r \ n' ou '\ n \ r' se estiver na caixa do windows ou mac. O mesmo vale para a análise de arquivos que representam dados tabulares; você pode definir as constantes FIELDSEPARATOR e RECORDSEPARATOR. Nesses casos, você está realmente definindo uma constante para representar um personagem que serve para uma determinada função. Ainda assim, se você fosse um programador iniciante, talvez nomeasse seu COMMA como separador de campo constante, sem perceber que deveria chamá-lo de FIELDSEPARATOR e, quando perceber, o código estará em produção e você estará no próximo projeto,

Finalmente, a prática que você descreve pode fazer sentido em alguns casos em que você escreve código para manipular dados codificados em uma codificação de caracteres específica, por exemplo, iso-8859-1, mas espera que a codificação mude posteriormente. É claro que, nesse caso, faria muito mais sentido usar bibliotecas de localização ou codificação e decodificação para lidar com isso, mas se, por algum motivo, você não pudesse usar essa biblioteca para lidar com problemas de codificação, usando constantes que você usaria apenas. redefinir em um único arquivo, em vez de literais codificados, espalhados por todo o código-fonte, pode ser um caminho a percorrer.

Quanto ao artigo ao qual você vinculou: Eu não acho que tente defender a substituição de literais de caracteres por constantes. Eu acho que está tentando ilustrar um método para usar interfaces para extrair constantes para outras partes da sua base de código. As constantes de exemplo usadas para ilustrar isso são muito mal escolhidas, mas não acho que sejam importantes.

Pascal
fonte
2
Eu acho que está tentando ilustrar um método para usar interfaces para extrair constantes para outras partes da sua base de código. que é um anti-padrão ainda pior e também possui forte acoplamento e baixa coesão, também não há razão válida para fazer isso.
3

Além de todas as boas respostas aqui, gostaria de acrescentar, como boa ideia, que uma boa programação é fornecer abstrações apropriadas que podem ser criadas por você e talvez por outras pessoas, sem precisar repetir o mesmo código repetidamente.

Boas abstrações tornam o código fácil de usar, por um lado, e fácil de manter, por outro.

Concordo totalmente que a DELIMITER=':'abstração em si é pobre, e apenas melhor do que COLON=':'(já que a última é totalmente empobrecida).

Uma boa abstração envolvendo seqüências de caracteres e separadores incluiria uma maneira de empacotar um ou mais itens de conteúdo individuais na cadeia de caracteres e descompactá-los também da cadeia de caracteres compactada, antes de mais nada, antes de dizer qual é o delimitador. Tal abstração seria agrupada como um conceito, na maioria dos idiomas como uma classe; por exemplo, para que seu uso seja praticamente auto-documentado, pois você pode procurar todos os locais em que essa classe é usada e ter certeza de qual é a intenção do programador em relação ao formato das seqüências compactadas em cada caso em que alguma abstração é usada.

Uma vez que tal abstração é fornecida, seria fácil usar sem nunca ter que consultar qual é o valor do DELIMITERou COLONé e, alterar os detalhes da implementação geralmente seria limitado à implementação. Portanto, em resumo, essas constantes devem realmente ser detalhes de implementação ocultos em uma abstração apropriada.

O principal atrativo do uso de constantes é que elas minimizam a manutenção quando uma mudança é necessária.

Boas abstrações, que são tipicamente composições de vários recursos relacionados, são melhores para minimizar a manutenção. Primeiro, eles separam claramente o fornecedor dos consumidores. Segundo, eles ocultam os detalhes da implementação e, em vez disso, fornecem funcionalidade diretamente útil. Terceiro, eles documentam em alto nível quando e onde estão sendo usados.

Erik Eidt
fonte
2

A única vez que vi essas constantes serem usadas com eficácia é corresponder a uma API ou documento existente. Vi símbolos como COMMAusados ​​porque um software em particular estava diretamente conectado a um analisador que era usado COMMAcomo tag em uma árvore de sintaxe abstrata. Eu também vi isso usado para corresponder a uma especificação formal. nas especificações formais, às vezes você vê símbolos como COMMAe não ','porque eles querem ser o mais claro possível.

Em ambos os casos, o uso de um símbolo nomeado como COMMAajuda a fornecer coesão a um produto separado. Esse valor geralmente supera o custo de notações excessivamente detalhadas.

Cort Ammon
fonte
2

Observe que você está tentando fazer uma lista.

Portanto, refatorar como: String makeList(String[] items)

Em outras palavras, fatore a lógica em vez dos dados .
Os idiomas podem ser diferentes na forma como representam listas, mas vírgulas são sempre vírgulas (isso é uma tautologia). Portanto, se o idioma mudar, alterar o caractere de vírgula não ajudará - mas isso ajudará.

Mehrdad
fonte
0

Se essa foi uma classe escrita como parte de um aplicativo pelo seu colega desenvolvedor, é quase certamente uma má ideia. Como outros já apontaram, faz sentido definir constantes como SEPARATOR = ','onde você pode alterar o valor e a constante ainda faz sentido, mas muito menos as constantes cujo nome descreve apenas seu valor.

No entanto, há pelo menos dois casos em que faz sentido declarar constantes cujo nome descreve exatamente seu conteúdo e onde você não pode alterar o valor sem alterar adequadamente o nome da constante:

  • Constantes matemáticas ou físicas, por exemplo PI = 3.14159. Aqui, o papel da constante é atuar como um mnemônico, já que o nome simbólico PIé muito mais curto e mais legível do que o valor que representa.
  • Listas exaustivas de símbolos em um analisador ou teclas em um teclado. Pode até fazer sentido ter uma lista de constantes com a maioria ou todos os caracteres Unicode e é aí que o seu caso pode se encaixar. Alguns personagens como Asão óbvios e claramente reconhecíveis. Mas você pode facilmente dizer Аe Adistante? O primeiro é o cirílico carta А enquanto o último é letra latina A . São letras diferentes, representadas por diferentes pontos de código Unicode, embora graficamente sejam quase idênticas. Prefiro ter constantes CYRILLIC_CAPITAL_AeLATIN_CAPITAL_Ano meu código, dois caracteres com aparência quase idêntica. Obviamente, isso não faz sentido se você souber que estará trabalhando apenas com caracteres ASCII que não contêm cirílico. Da mesma forma: eu uso o alfabeto latino todos os dias, portanto, se eu estivesse escrevendo um programa que precisava de um caractere chinês, provavelmente preferiria usar uma constante em vez de inserir um caractere que não entendo. Para alguém que usa caracteres chineses diariamente, um caractere chinês pode ser óbvio, mas um latim pode ser mais fácil de representar como uma constante nomeada. Então, como você vê, depende do contexto. Ainda assim, uma biblioteca pode conter constantes simbólicas para todos os caracteres, pois os autores não podem saber antecipadamente como a biblioteca será usada e quais caracteres podem precisar de constantes para melhorar a legibilidade em um aplicativo específico.

No entanto, esses casos geralmente são tratados por classes de sistema ou bibliotecas para fins especiais e sua ocorrência no código escrito pelos desenvolvedores de aplicativos deve ser muito rara, a menos que você esteja trabalhando em algum projeto muito especial.

Michał Kosmulski
fonte
-1

Talvez.

Constantes de caractere único são relativamente difíceis de distinguir. Portanto, pode ser fácil esquecer o fato de você adicionar um ponto ao invés de vírgula

city + '.' + state

considerando que esse é um erro relativamente difícil de cometer

city + Const.PERIOD + state

Dependendo do seu ambiente de internacionalização e globalização, a diferença entre um apóstrofo ASCII e o apóstrofo aberto e fechado do Windows-1252 (ou as aspas duplas ASCII e as aspas duplas de abertura e fechamento do Windows-1252) pode ser significativa e é notoriamente difícil de visualizar. no código.

Agora, presumivelmente, se colocar um ponto por engano em vez de vírgula fosse um problema funcional significativo, você teria um teste automatizado que encontraria o erro de digitação. Se o seu software estiver gerando arquivos CSV, eu esperaria que sua suíte de testes descobrisse rapidamente que você teve um período entre a cidade e o estado. Se seu software deve ser executado para clientes com uma variedade de configurações de internacionalização, presumivelmente, seu conjunto de testes será executado em cada ambiente e será ativado se você tiver uma cotação aberta da Microsoft se pretender um apóstrofo.

Eu poderia imaginar um projeto em que fazia mais sentido optar por um código mais detalhado que pudesse resolver esses problemas, principalmente quando você tem um código mais antigo que não possui um conjunto de testes abrangente, mesmo que eu provavelmente não codifique dessa maneira. um projeto de desenvolvimento de campo verde. E adicionar uma constante para cada caractere de pontuação em vez de apenas aqueles que são potencialmente problemáticos em seu aplicativo em particular é provavelmente um exagero.

Justin Cave
fonte
2
o que acontece quando algum idiota muda Const.PERIODpara ser igual a ~? Não há justificativa para uma tautologia de caracteres nomeados, apenas adiciona manutenção e complexidade desnecessárias nos ambientes de programação modernos. Você vai escrever um conjunto de testes de unidade que basicamente dizem assert(Const.PERIOD == '.')?
3
@JarrodRoberson - Isso seria péssimo, com certeza. Mas você teria tantos problemas se alguém adicionasse uma constante Unicode que se parece quase exatamente com uma vírgula, em vez de uma vírgula real. Como eu disse, esse não é o tipo de coisa que eu faria em um projeto de desenvolvimento greenfield. Mas se você tiver uma base de código legada com um conjunto de testes irregular, em que tropeçou na vírgula / período ou apóstrofo / apóstrofo / abominação da Microsoft apóstrofe algumas vezes, criar algumas constantes e dizer às pessoas para usá-las pode ser uma maneira razoável de fazer isso. o código melhor sem gastar um ano escrevendo testes.
Justin Cave
3
Se seu exemplo legado é ruim, acabei de refatorar uma base de mais de 1.000.000 de códigos LOC com 18 anos de idade. Ele tinha todos os caracteres imprimíveis definidos dessa maneira várias vezes, com diferentes nomes conflitantes. E muitas vezes as coisas nomeadas COMMAforam realmente definidas = SPACE + "," + SPACE. Sim, algum idiota tinha uma SPACEconstante. Eu refatorei todos eles e o código era mais legível e as contratações das faculdades eram muito mais capazes de rastrear as coisas e corrigi-las sem ter seis níveis de indireção para descobrir como algo estava realmente definido.
-1

As constantes de um caractere são melhores que as literais?

Há muitas confusões flutuando por aqui. Deixe-me ver se consigo separá-los.

As constantes fornecem:

  • semântica
  • mudança, durante o desenvolvimento
  • indireção

Passar para um único nome de caractere afeta apenas a semântica. Um nome deve ser útil como comentário e claro no contexto. Deve expressar significado, não o valor. Se ele pode fazer tudo isso com um único caractere fino. Se não puder, por favor não.

Um literal e uma constante podem mudar durante o desenvolvimento. É isso que traz a questão do número mágico. Strings também podem ser números mágicos.

Se o significado semântico existe, e como ambos são constantes, se a constante tem mais valor do que um literal se resume à indireção.

Indirecionar pode resolver qualquer problema, além de muito indireto.

O indireto pode resolver o problema do número mágico porque permite que você decida o valor de uma ideia em um só lugar. Semanticamente, para que isso valha a pena, o nome deve deixar claro que essa ideia é clara. O nome deve ser sobre a ideia, não o valor.

O indireto pode ser exagerado. Alguns preferem pesquisar e substituir literais para fazer suas alterações. Tudo bem, desde que 42 seja claramente o significado da vida e não seja misturado com 42, o número atômico de molibdênio.

Para onde você pode fazer distinções úteis como essa com uma única letra depende muito do contexto. Mas eu não faria disso um hábito.

candied_orange
fonte
11
Semântica é a chave. Se e "A" tiver mais semântica do que simplesmente ser um "A", vale a pena vincular a mesma semântica à mesma "referência". Não importa se é uma constante ou não. Eu concordo totalmente.
oopexpert
-1

Como contraponto filosófico à opinião da maioria, devo afirmar que há alguns de nós que apreciam o programador camponês francês não sofisticado do século XIX e

lembrava-se de sua lucidez monótona e eterna, de suas visões estupidamente sensatas de tudo, de seu contentamento colossal com os truques, simplesmente porque eram verdadeiros. "Confunda tudo!" gritou Turnbull para si mesmo: "Se ele está no asilo, não pode haver ninguém lá fora".

GK Chesterton, A Bola e A Cruz

Não há nada errado em apreciar a verdade e não há nada errado em afirmar a verdade, especialmente quando se fala com um computador.

Se você mentir para o computador, ele o levará

Perry Farrar - Germantown, Maryland (de Mais pérolas de programação)


Mas, na maioria das vezes, concordo com as pessoas que dizem que é burra. Sou jovem demais para ter aprendido a programar o FORTRAN, mas ouvi dizer que você pode redefinir 'A' = 'Q'e criar todos os tipos de criptogramas maravilhosos. Você não está fazendo isso.

Além dos problemas da i18n mencionados anteriormente (que não estão redefinindo o glifo "COMMA", mas realmente redefinindo o glifo de um DECIMAL_POINT). Construir aspas francesas de cenoura ou aspas simples britânicas para transmitir significado aos seres humanos está pronto e essas realmente devem ser variáveis, não constantes. A constante seria AMERICAN_COMMA := ','e acomma := AMERICAN_COMMA

E, se eu estivesse usando um padrão de construtor para construir uma Consulta SQL, preferiria ver

sb.append("insert into ")
 .append(table_name)
 .append(" values ")
 .append(" ( ")
 .append(val_1)
 .append(",")
 .append(val_2)
 .append(" ); ")

do que qualquer outra coisa, mas se você adicionasse constantes, seria

INSERT_VALUES_START = " ( "
INSERT_VALUES_END = " ) "
INSERT_VALUES_SEPARATOR = " , "
QUERY_TERMINATOR = ";"

sb.append("insert into ")
 .append(table_name)
 .append(" values ")
 .append(INSERT_VALUES_START)
 .append(val_1)
 .append(INSERT_VALUES_SEPARATOR)
 .append(val_2)
 .append(INSERT_VALUES_END)
 .append(QUERY_TERMINATOR)

No entanto, se você já assistiu a outra pessoa programar (ou digitar), poderá notar algumas peculiaridades interessantes. Nem todos nós somos datilógrafos estelares. Muitos de nós começamos a programar tarde ou fomos criados com teclados soviéticos (onde as teclas digitam em você) e gostamos de recortar e colar letras individuais em vez de tentar encontrá-las no teclado e / ou confiar no preenchimento automático.

Nada vai preencher automaticamente uma string para você; portanto, se eu puder obter uma vírgula pressionando 'con', alt-espaço, baixo, baixo, baixo, baixo, digite e obtenha uma cotação pressionando 'con', alt-space, baixo, para baixo, entre. Talvez eu faça exatamente isso.


Outra coisa a lembrar sobre literais de strings é a maneira como eles são compilados. Pelo menos no Delphi, (que é a única linguagem que obcecado sobre a pilha de), você terminará seus literais aparecendo na pilha de cada função. Então, muitos literais = muita sobrecarga de função; "," na função_A não é o mesmo pedaço de memória que um "," na função_B ". Para combater isso, existe uma" cadeia de recursos "que pode ser criada e vinculada lateralmente - e é assim que eles fazem coisas i18n (matando dois pássaros com um arbusto.) No Python, todos os seus literais de seqüência de caracteres são objetos, e pode até parecer bom de usar utils.constants.COMMA.join(["some","happy","array","strings"]), mas não é uma idéia estelar para os pontos repetidos repetidamente nesta página.

Peter Turner
fonte
-4

Mas quando vamos começar a usar um símbolo diferente de ',' para representar uma vírgula?

Para localização.

Nos países de língua inglesa, o símbolo que separa as partes inteira e fracionária de um decimal é ".", Que chamamos de "ponto decimal". Em muitos outros países, o símbolo é "," e normalmente é chamado o equivalente a "vírgula" no idioma local. Da mesma forma, onde os países de língua inglesa usam "," para separar grupos de três dígitos em números grandes (como 1.000.000 por um milhão), os países que usam vírgula como ponto decimal usam um ponto (1.000.000).

Portanto, é possível criar constantes DECIMAL_POINT e COMMA se você estiver fazendo globalização.

Paul G
fonte
2
Mas COMMA e DECIMAL_POINT não são os nomes corretos para as entidades (provavelmente o motivo pelo qual você recebeu votos negativos).
Kyle Strand
Você precisaria compilar versões localizadas específicas. Constantes literais não são adequadas para isso; esse caso de uso exigiria arquivos de definição e pesquisas neles (que podem envolver constantes, mas constantes de pesquisa, não caracteres constantes).