Les constantes à un caractère sont-elles meilleures que les littéraux?

127

J'ai récemment rencontré une classe qui fournit à peu près tous les caractères uniques comme constante; de tout COMMAà BRACKET_OPEN. Vous vous demandez si cela était nécessaire; Je lis un « article » qui suggère qu'il pourrait être utile de tirer littéraux caractère unique en constantes. Donc, je suis sceptique.

Le principal attrait de l'utilisation des constantes est qu'elles minimisent la maintenance lorsqu'un changement est nécessaire. Mais quand allons-nous commencer à utiliser un symbole différent de "," pour représenter une virgule?

La seule raison pour laquelle je vois utiliser des constantes au lieu de littéraux est de rendre le code plus lisible. Mais est-ce que city + CharacterClass.COMMA + state(par exemple) est vraiment plus lisible que city + ',' + state?

Pour moi, les inconvénients l'emportent sur les avantages, principalement que vous introduisiez une autre classe et une autre importation. Et je crois en moins de code si possible. Alors, je me demande quel est le consensus général ici.

Austin Day
la source
33
Hmm ... cela pourrait être utile pour différents endroits, peut-être? Par exemple, certaines langues utilisent des guillemets (guillemets d'angle, «et ») comme guillemets au lieu du standard anglais "(ou plus joli et ). En dehors de cela, cela ressemble à un ensemble de personnages magiques. En supposant que deux instances de CharacterClasscalled englishCharset frenchChars, il est possible que englishChars.LEFT_QUOTEcela soit , alors que cela frenchChars.LEFT_QUOTEpourrait être «.
Justin Time
4
Il existe de nombreuses variantes sur les virgules: en.wikipedia.org/wiki/Comma#Comma_variants - peut-être que ce n'est pas une idée aussi stupide, surtout si votre code source peut être encodé en tant que utf-8.
Aaron Hall
21
Dans votre cas, c'est comme appeler une variable "nombre". Votre constante aurait dû s'appeler DELIMITER. Ou cela devrait être CITY_STATE = "{0}, {1}"
the_lotus
13
Cet article que vous avez lié est très terrible. Les constantes ne devraient jamais être jetées dans un seau comme celui-là. Placez-les sur les classes où ils ont un contexte: la classe avec la constante fournit essentiellement le contexte dans lequel la constante est utilisée. Par exemple, Java File.separator. La classe vous indique le type de séparateur. Avoir une classe nommée Constsou Constantsne fournissant aucun contexte et rendant les constantes plus difficiles à utiliser correctement.

Réponses:

183

Tautologie :

Il est très clair, si vous lisez la toute première phrase de la question, que cette question ne concerne pas des utilisations appropriées, telles que l’ élimination des nombres magiques , mais au mieux une terrible cohérence insensée . Quel est ce que cette réponse adresse

Le bon sens vous dit que const char UPPER_CASE_A = 'A';ou const char A = 'A'ne pas ajouter quoi que ce soit , mais l' entretien et de la complexité de votre système. const char STATUS_CODE.ARRIVED = 'A'est un cas différent.

Les constantes sont supposées représenter des éléments immuables au moment de l'exécution, mais devront peut-être être modifiées à l'avenir au moment de la compilation. Quand serait const char A =bien égal autre chose que A?

Si vous voyez public static final char COLON = ':'du code Java, trouvez qui a écrit ça et cassez leurs claviers. Si la représentation COLONchange pour toujours, :vous aurez un cauchemar de maintenance.

Obfuscation:

Que se passe-t-il quand quelqu'un le change COLON = '-'parce que là où ils l'utilisent a besoin d'un -partout partout? Allez-vous écrire des tests unitaires qui indiquent essentiellement assertThat(':' == COLON)pour chaque constréférence unique afin de s'assurer qu'ils ne sont pas modifiés? Seulement pour que quelqu'un répare le test quand ils le changent?

Si quelqu'un prétend réellement que cela public static final String EMPTY_STRING = "";est utile et bénéfique, vous venez de qualifier ses connaissances et de les ignorer en toute sécurité pour tout le reste.

Le fait de disposer de tous les caractères imprimables disponibles avec une version nommée montre simplement que quiconque l'a fait n'est pas qualifié pour écrire du code sans surveillance.

Cohésion:

Cela réduit aussi artificiellement la cohésion, car cela éloigne les objets de ceux qui les utilisent et qui leur sont liés.

En programmation informatique, la cohésion fait référence au degré d'appartenance des éléments d'un module. Ainsi, la cohésion mesure la force de la relation entre les différentes fonctionnalités d'un module donné. Par exemple, dans les systèmes hautement cohésifs, la fonctionnalité est étroitement liée.

Couplage:

Il associe également de nombreuses classes non apparentées car elles finissent toutes par référencer des fichiers qui ne sont pas vraiment liés à ce qu'ils font.

Le couplage étroit se produit lorsqu'un groupe de classes est fortement dépendant les unes des autres. Ce scénario se produit lorsqu'une classe assume trop de responsabilités ou lorsqu'une préoccupation concerne plusieurs classes plutôt que d'avoir sa propre classe.

Si vous avez utilisé un nom plus comme DELIMITER = ','vous avez toujours le même problème, parce que le nom est générique et ne porte aucune sémantique. Réaffecter la valeur ne fait rien de plus pour aider à faire une analyse d’impact que de chercher et de remplacer le littéral ','. Parce que quel code utilise-t-il et a-t-il besoin du ,et un autre code utilise mais a besoin ;maintenant? Encore faut-il regarder chaque utilisation manuellement et les changer.

Dans la nature:

J'ai récemment refactoré une 1,000,000+ LOCapplication de 18 ans. Il y avait des choses comme public static final COMMA = SPACE + "," + SPACE;. Ce n’est pas mieux que de simplement indiquer le " , "cas échéant.

Si vous voulez faire valoir la lisibilité, vous devez apprendre à configurer votre IDE pour qu'il affiche les whitespacecaractères où vous pouvez les voir ou quoi que ce soit, c'est une raison extrêmement compliquée d'introduire l'entropie dans un système.

Il avait également ,défini plusieurs fois avec plusieurs fautes d'orthographe du mot COMMAdans plusieurs packages et classes. Avec des références à toutes les variations mélangées ensemble dans le code. Essayer de réparer quelque chose sans casser quelque chose de complètement indépendant n’était rien de moins qu’un cauchemar .

Même avec l'alphabet, il y avait plusieurs UPPER_CASE_A, A, UPPER_A, A_UPPERque la plupart du temps étaient égaux , A mais dans certains cas , n'étaient pas . Pour presque tous les personnages, mais pas tous.

Et d'après l'historique des éditions, il ne semble pas qu'un seul d'entre eux ait été édité ou modifié au cours des 18 dernières années. En effet, ce qui devrait être une raison évidente est que cela casserait trop d'éléments cachés. Vous avez donc une nouvelle variable. noms qui indiquent la même chose et qui ne peuvent jamais être modifiés pour la même raison.

Dans aucune réalité sensée, ne pouvez-vous affirmer que cette pratique ne fait que commencer à l'entropie maximale.

J'ai refactoré tout ce gâchis et mis en ligne toutes les tautologies et les nouvelles recrues des collèges ont été beaucoup plus productives, car elles n'étaient pas obligées de chasser à travers plusieurs niveaux d'indirection ce que ces constréférences indiquaient réellement, car elles n'étaient pas fiables dans ce qu'elles s'appelaient vs ce qu'ils contenaient.


la source
112
Peut-être devriez-vous ajouter un contre-exemple: ce const char DELIMITER = ':'serait vraiment utile.
Bergi
115
Je voudrais faire plusieurs arguments qui EMPTY_STRINGsont bénéfiques. (1) Je trouve beaucoup plus facilement toutes les utilisations de EMPTY_STRINGdans un fichier que toutes les utilisations de "". (2) quand je vois que EMPTY_STRINGje sais avec certitude que le développeur voulait que cette chaîne soit vide et qu'il ne s'agisse pas d'une mauvaise édition ni d'un paramètre fictif pour qu'une chaîne soit fournie ultérieurement. Maintenant, vous prétendez que par mon argument, vous pouvez qualifier mes connaissances et m'ignorer en toute sécurité pour toujours. Alors, comment qualifiez-vous mes connaissances? Et avez-vous l'intention d'ignorer mon conseil pour toujours? Je n'ai aucun problème de toute façon.
Eric Lippert
39
@immibis: Nous pouvons cesser de penser que ces éléments sont utiles dans le contexte de la gestion du changement. Ce sont des constantes. Ils ne changent pas. Considérez-les comme utiles dans le contexte des humains qui recherchent et comprennent la sémantique du code . Savoir que quelque chose est un délimiteur clé-valeur-paire est beaucoup plus utile que de savoir que c'est un colon; c'est un fait concernant le domaine sémantique de la préoccupation du programme, pas sa syntaxe .
Eric Lippert
15
@EricLippert: Je vois un peu le point de vue d'autres personnes ici qui soulignent que la seule garantie qu'un constfournit est qu'il ne changera pas au moment de l'exécution (après la compilation), bien que je sois d'accord avec vous pour dire que le sens sémantique du mot constest beaucoup plus important que son utilisation en tant qu’outil de gestion du changement. Cela dit, je peux certainement imaginer un const EARLIEST_OS_SUPPORTEDmodèle non seulement cohérent sur le plan sémantique, mais qui évoluera également avec le temps, à mesure que le programme évolue et que les anciennes méthodes sont supprimées.
Robert Harvey
16
@ DanielJour: Il s'agit donc d'un troisième argument pour EMPTY_STRING; qu'un IDE bien conçu fera apparaître des outils qui me permettront de traiter cette entité de manière symbolique plutôt que syntaxique. Généralisez ceci à un quatrième argument: la bibliothèque d'outils d'analyse de code située sous l'EDI peut permettre une analyse programmatique avancée de la correction du code au niveau symbolique . Un développeur qui souhaite exploiter des outils plus avancés que ceux écrits il y a 40 ans ne doit que légèrement modifier ses habitudes afin de tirer parti des avantages d'un outillage avancé.
Eric Lippert
145

Le principal attrait de l'utilisation des constantes est qu'elles minimisent la maintenance lorsqu'un changement est nécessaire.

ABSOLUMENT PAS. Ce n’est pas du tout la raison d’utiliser des constantes car les constantes ne changent pas par définition . Si une constante change, alors ce n'était pas une constante, n'est-ce pas?

L'attrait de l'utilisation de constantes n'a absolument rien à voir avec la gestion du changement ni avec le fait de rendre les programmes susceptibles d'être écrits, compris et maintenus par les utilisateurs . Si je veux savoir partout dans mon programme où deux points sont utilisés en tant que séparateur d'URL, je peux le savoir très facilement si j'ai la discipline pour définir un URLSeparator constant, et ne peux pas savoir si facilement du tout si je dois le faire pour grep :et obtenir chaque place dans le code où :est utilisé pour indiquer une classe de base, un ?:opérateur ou autre.

Je suis tout à fait en désaccord avec les autres réponses selon lesquelles il s’agit là d’une perte de temps inutile. Les constantes nommées apportent une signification à un programme, et cette sémantique peut être utilisée à la fois par les humains et par les machines pour comprendre un programme plus en profondeur et le maintenir plus efficacement.

Le truc ici n'est pas d'éviter les constantes, mais plutôt de les nommer avec leurs propriétés sémantiques plutôt que leurs propriétés syntaxiques . À quoi sert la constante? N'appelez cela Commaque si le domaine d'activité de votre programme est la typographie, l'analyse syntaxique en anglais, etc. Appelez ça ListSeparatorou quelque chose comme ça , pour que la sémantique de la chose soit claire.

Eric Lippert
la source
42
Bien que je sois d’accord avec l’esprit de ce que vous dites ici, vos deuxième / troisième phrases ne sont pas vraiment correctes. Une constante peut changer entre les versions d'un fichier. En fait, la plupart des programmes que j’écris ont une constante nommée quelque chose comme MY_VER, qui contient le numéro de version actuel du programme, qui peut ensuite être utilisée dans le reste du programme plutôt qu’une chaîne magique comme "5.03.427.0038". L'avantage supplémentaire est que vous dites que cela fournit des informations sémantiques.
Monty Harder
50
Pour être juste, l’intérêt d’une constante est qu’elle ne change pas pendant l’exécution après son initialisation, pas entre les compilations. Du point de vue du compilateur, le fait est que le compilateur peut supposer que le programme est incapable de le modifier. si le programmeur est autorisé à le modifier lors de la recompilation ne change pas sa constante. Il peut également y avoir des cas où le logiciel utilise une valeur matérielle en lecture seule, par exemple en déréférencant un const volatile T*pointeur sur une adresse prédéterminée; alors que le programme ne peut pas le changer, le matériel le peut.
Justin Time
6
@MontyHarder: Bon point. Mon opinion est éclairée par le fait que j'utilise généralement des langages qui distinguent les constantes - qui doivent rester inchangées - et les variables qui peuvent être affectées une fois - qui peuvent changer d'une version à l'autre, d'une exécution à l'autre, etc. Une constante et une variable sont des choses différentes; on reste le même et on varie dans le temps.
Eric Lippert
7
@SteveCox: Je suis d'accord. la façon dont C / C ++ caractérise "const" est étrange et d’utilisation limitée. La propriété que je veux des constantes est que leurs valeurs ne changent pas, pas que je ne puisse les changer dans certaines fonctions mais pas dans d'autres.
Eric Lippert
15
"Ce n'est pas du tout la raison d'utiliser des constantes car les constantes ne changent pas par définition. Si une constante change jamais, alors ce n'était pas une constante, n'est-ce pas?" Changer les constantes au moment de la compilation (et non pas du temps d'exécution évidemment) est parfaitement normal. C'est pourquoi vous en avez fait une "chose" clairement étiquetée. Bien sûr, les constantes de l'OP sont indésirables, mais penser à quelque chose comme const VERSION='3.1.2'ou const KEYSIZE=1024ou autre.
AnoE
61

Non, c'est idiot.

Ce qui n’est pas forcément stupide, c’est d’insérer de telles choses dans des étiquettes nommées pour des raisons de localisation. Par exemple, le séparateur de milliers est une virgule en Amérique (1 000 000), mais pas dans d’autres paramètres régionaux. Le placer dans une étiquette nommée (avec un nom approprié, sans virgule) permet au programmeur d’ignorer / d’abstraire ces détails.

Mais faire une constante parce que "les cordes magiques sont mauvaises" n’est que culte.

Telastyn
la source
8
La localisation est généralement plus compliquée que les seules constantes de chaîne. Par exemple, certaines langues veulent un délimiteur de liste entre tous les éléments de la liste, tandis que d'autres excluent le délimiteur avant le dernier élément. Donc, en général, on n'a pas besoin de constantes localisées, mais de règles localisées .
Vlad
19
En réalité, le séparateur de milliers n'est pas nécessairement un séparateur de milliers dans d'autres régions (Chine / Japon). Il n'est même pas défini après un nombre constant de chiffres (Inde). Oh, et il peut y avoir des délimiteurs différents selon qu'il s'agit d'un séparateur de 1000 ou du séparateur de 1000000 (Mexique). Mais c'est moins un problème que de ne pas utiliser les chiffres ASCII 0 à 9 dans certaines langues (Farsi). ux.stackexchange.com/questions/23667/…
Peter
1
@Vlad La localisation est beaucoup plus complexe que cela, cependant, le séparateur de milliers est un exemple bien connu que les gens reconnaissent.
Cela dépend de la stratégie de localisation ... changez-vous toutes les constantes de votre programme pour le traduire? Ou devriez-vous plutôt lire les valeurs d'un fichier (ou d'un autre magasin de données), ce qui en fait des variables d'exécution?
Paŭlo Ebermann
Ce ne serait pas du tout utile comme une constante, alors. Le programme aurait besoin d'être recompilé pour les paramètres régionaux, ce qui est une pratique affreuse. Elles doivent être des variables chargées à partir de fichiers de définition et recherchées au besoin. Non pas que je ne sois pas d’accord avec le point (j’ai voté pour la réponse), mais j’aimerais prendre une position plus dure à ce sujet.
29

Quelques caractères peuvent être ambigus ou sont utilisés à plusieurs fins. Par exemple, nous utilisons '-'un trait d'union, un signe moins ou même un tiret. Vous pouvez faire des noms séparés comme:

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

Plus tard, vous pourrez choisir de modifier votre code afin de lever l’ambiguïté en le redéfinissant comme suit:

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

C'est peut-être pour cette raison que vous envisageriez de définir des constantes pour certains caractères uniques. Cependant , le nombre de caractères qui sont ambigus de cette manière est petit. Tout au plus, il semblerait que vous ne le fassiez que pour ceux-là. Je soutiens également que vous pouvez attendre jusqu'à ce que vous ayez réellement besoin de distinguer les caractères ambigus avant de factoriser le code de cette manière.

Les conventions typographiques pouvant varier selon les langues et les régions, il est probablement préférable de charger une ponctuation ambiguë à partir d'une table de traduction.

Adrian McCarthy
la source
Pour moi, c'est la seule raison valable pour laquelle nous pourrions créer des constantes de caractère
FP
2
L'utilisation -comme un tiret est assez trompeuse ... c'est beaucoup trop court pour cela dans la plupart des polices. (Il est même plus court qu'un tiret.)
Paŭlo Ebermann
OK, pas le meilleur exemple. J'ai commencé avec les strings plutôt wchar_tet ai utilisé la convention de manuscrit standard de "--"pour le tiret. Mais l'exemple original utilisait des caractères uniques, alors je me suis tourné pour rester fidèle à la question. Il y a des gens qui -tapent pour les tirets, surtout quand on travaille dans une police à pas fixe.
Adrian McCarthy
1
@ PaŭloEbermann Non, traditionnellement un tiret em correspond à la largeur du caractère 'm' d'un caractère et un tiret en correspond à la largeur d'un caractère 'n'.
Dizzley
@ Dizzley oui, et tiret-largeur <n-largeur <m-largeur.
Paŭlo Ebermann
22

Une constante doit ajouter un sens.

Définir COMMA comme une virgule n'ajoute pas de signification, car nous savons qu'une virgule est une virgule. Au lieu de cela, nous détruisons le sens, car maintenant, COMMA pourrait ne plus être une virgule.

Si vous utilisez une virgule dans un but et souhaitez utiliser une constante nommée, attribuez-lui un nom. Exemple:

  • city + CharacterClass.COMMA + state = mauvais
  • city + CITY_STATE_DELIMITER + state = bien

Utiliser des fonctions pour le formatage

Personnellement, je préfère FormatCityState(city, state)et ne me soucie pas de voir à quoi ressemble le corps de cette fonction tant qu'elle est courte et réussit les tests.

Peter
la source
1
Ah, mais une virgule n'est pas toujours la même virgule. Je pourrais définir COMMA = '\ u0559' ou '\ u060C' etc. (voir Unicode) ou même le transformer en une variable plus tard et le lire à partir d'un fichier de configuration. De cette façon, cela aura toujours le même sens , mais juste une valeur différente. Que diriez-vous de cela
M. Lister
2
@ MrLister: YAGNI. Si vous avez ce besoin: génial! Vous avez une bonne solution. Mais si vous ne le faites pas, n'encombrez pas votre code, car vous pourriez peut-être un jour le faire. De plus, d'après mon expérience, si vous essayez d'introduire des abstractions sans fonction dans votre base de code, les gens ne sont pas très doués pour être cohérents. Ainsi, même si vous définissiez COMMA dans le but d'utiliser un autre codet, dans un programme de taille et d'âge suffisants pour que le choix compte, vous constaterez probablement que la constante n'a pas été utilisée partout où elle aurait dû l'être. été (et inversement, peut avoir été utilisé de manière inappropriée aussi).
Eamon Nerbonne
17

L'idée qu'une constante COMMA est meilleure ','ou ","plutôt facile à démystifier. Bien sûr, il y a des cas où cela a du sens, par exemple en faisant final String QUOTE = "\"";beaucoup d'économies sur la lisibilité sans toutes les barres obliques, mais en excluant les caractères de contrôle de la langue tels que \ 'et "je ne les ai pas trouvés très utiles.

Utiliser final String COMMA = ","n'est pas seulement une mauvaise forme, c'est dangereux! Quand quelqu'un veut changer le séparateur de ","en, ";"il peut changer le fichier de constantes COMMA = ";"car c'est plus rapide pour eux et ça marche. Sauf que, vous savez, toutes les autres choses qui utilisent maintenant COMMA sont aussi des points-virgules, y compris des choses envoyées à des consommateurs externes. Donc, il passe tous vos tests (parce que tout le code de marshalling et unmarshalling utilisait également COMMA), mais les tests externes échoueront.

Ce qui est utile, c'est de leur donner des noms utiles. Et oui, parfois, plusieurs constantes auront le même contenu mais des noms différents. Par exemple final String LIST_SEPARATOR = ",".

Votre question est donc la suivante: "les constantes à un seul caractère sont-elles meilleures que les littéraux" et la réponse est clairement non, elles ne le sont pas. Mais, mieux encore, un nom de variable à portée étroite qui indique explicitement son objectif. Bien sûr, vous passerez quelques octets supplémentaires sur ces références supplémentaires (en supposant qu'elles ne soient pas compilées sur vous, ce qui sera probablement le cas), mais pour la maintenance à long terme, qui représente la majeure partie du coût d'une application, valent le temps de faire.

CorsiKa
la source
Que diriez-vous de définir conditionnellement DISP_APOSTROPHE comme un caractère de guillemet simple à droite ASCII 0x27 ou Unicode (qui est un rendu plus approprié typographiquement d'une apostrophe), en fonction de la plate-forme cible?
Supercat
3
en fait, l’ QUOTEexemple prouve que c’est également une mauvaise idée puisque vous l’assignez à ce qui est généralement / populairement connu sous le nom de DOUBLE QUOTEet QUOTEimplique SINGLE_QUOTEce qu’on appelle plus correctement APOSTROPHE.
3
@JarrodRoberson Je ne pense pas que citation implique une citation unique, personnellement - mais c'est une autre bonne raison d'éliminer toute ambiguïté là où vous le pouvez!
CorsiKa
2
Je n'aime pas cet QUOTEexemple pour une raison supplémentaire: il rend encore plus difficile la lecture de chaînes de caractères construites avec. Il "Hello, my name is " + QUOTE + "My Name" + QUOTEs'agit d'un exemple trivial et pourtant, il a toujours l'air mauvais. Oh, bien sûr, au lieu de la concaténation, vous pouvez utiliser des jetons de remplacement, cela "Hello, my name is %sMy Name%s".format(QUOTE, QUOTE)pourrait aussi être pire. Mais, hé, essayons des jetons indexés "Hello, my name is {0}My Name{0}".format(QUOTE), pas tellement mieux. Toute chaîne non triviale générée avec des guillemets serait encore pire.
VLAZ
2
@corsiKa - Je vais vivre avec les citations réelles échappées. Si j'en manque un, l'IDE que j'utilise se plaindra immédiatement. Le code ne sera probablement pas compilé non plus. C'est assez facile à repérer. Comme il est facile de se tromper, "My name is" + QUOTE + "My Name" + QUOTEj’ai fait la même erreur trois fois en écrivant le commentaire ci-dessus. Peux tu le repérer? Si cela vous prend un peu, il est l'espace manquant après est . Formatez-vous la chaîne? Dans ce cas, une chaîne avec plusieurs jetons à remplacer sera encore pire à résoudre. Comment dois-je l'utiliser pour qu'il soit plus lisible?
VLAZ
3

J'ai écrit des lexers et des analyseurs syntaxiques et utilisé des constantes de nombres entiers pour représenter les terminaux. Par souci de simplicité, les terminaux à un seul caractère ont eu le code ASCII comme valeur numérique, mais le code aurait pu être tout à fait autre chose. Donc, j'aurais un T_COMMA qui aurait reçu le code ASCII pour ',' comme valeur constante. Cependant, il y avait aussi des constantes pour les non-finales auxquelles étaient attribués des entiers supérieurs au jeu ASCII. En regardant des générateurs d’analyseurs tels que yacc ou bison ou des analyseurs écrits en utilisant ces outils, j’ai eu l’impression que c’était comme ça que tout le monde l’avait fait.

Ainsi, alors que, comme tout le monde, je pense qu'il est inutile de définir des constantes dans le but explicite d'utiliser les constantes au lieu des littéraux dans votre code, je pense qu'il existe des cas extrêmes (analyseurs syntaxiques, par exemple) où vous pourriez rencontrer du code épineux des constantes telles que celles que vous décrivez. Notez que dans le cas de l'analyseur, les constantes ne sont pas seulement là pour représenter les littéraux de caractères; ils représentent des entités qui pourraient tout simplement se passent comme caractère littéraux.

Je peux penser à quelques cas plus isolés où il pourrait être judicieux d'utiliser des constantes plutôt que les littéraux correspondants. Par exemple, vous pouvez définir NEWLINE comme étant le littéral '\ n' sur une boîte unix, mais '\ r \ n' ou '\ n \ r' si vous êtes sous Windows ou une boîte mac. Il en va de même pour l'analyse de fichiers représentant des données tabulaires. vous pouvez définir les constantes FIELDSEPARATOR et RECORDSEPARATOR. Dans ces cas, vous définissez en fait une constante pour représenter un caractère qui remplit une certaine fonction. Néanmoins, si vous étiez un programmeur débutant, vous pourriez peut-être nommer votre séparateur de champ constant COMMA, sans vous rendre compte que vous auriez dû l'appeler FIELDSEPARATOR, et au moment où vous vous en rendrez compte, le code serait en production et vous seriez au prochain. projet,

Enfin, la pratique que vous décrivez peut sembler judicieuse dans quelques cas où vous écrivez du code pour traiter des données codées dans un codage de caractère spécifique, par exemple iso-8859-1, mais attendez-vous à ce que le codage change ultérieurement. Bien sûr, dans un tel cas, il serait beaucoup plus judicieux d’utiliser des bibliothèques de localisation, d’encodage et de décodage pour le gérer, mais si, pour une raison quelconque, vous ne pouviez pas utiliser une telle bibliothèque pour traiter les problèmes d’encodage pour vous, utilisez uniquement des constantes. avoir à redéfinir dans un seul fichier au lieu de littéraux codés en dur jonchant tout votre code source pourrait être une solution.

En ce qui concerne l’article que vous avez lié: Je ne pense pas qu’il essaie de justifier le remplacement de littéraux de caractères par des constantes. Je pense qu'il s'agit d'essayer d'illustrer une méthode d'utilisation d'interfaces pour extraire des constantes dans d'autres parties de votre base de code. Les constantes d'exemple utilisées pour illustrer ceci sont très mal choisies, mais je ne pense pas qu'elles importent en rien.

Pascal
la source
2
Je pense qu'il s'agit d'essayer d'illustrer une méthode d'utilisation d'interfaces pour extraire des constantes dans d'autres parties de votre base de code. ce qui est un anti-modèle encore pire, un couplage étroit et une cohésion faible également, il n’ya aucune raison valable de le faire non plus.
3

En plus de toutes les bonnes réponses ici, j'aimerais ajouter comme matière à réflexion, qu'une bonne programmation consiste à fournir des abstractions appropriées sur lesquelles vous pouvez construire, vous-même et peut-être d'autres, sans avoir à répéter le même code encore et encore.

Les bonnes abstractions rendent le code facile à utiliser d'une part, et à maintenir de l'autre.

Je suis tout à fait d’accord pour dire que cette DELIMITER=':'abstraction est en soi une piètre abstraction, et qu’elle est simplement meilleure que COLON=':'(car cette dernière est totalement appauvrie).

Une bonne abstraction impliquant des chaînes et des séparateurs inclurait un moyen d'empaqueter un ou plusieurs éléments de contenu individuels dans la chaîne et de les décompresser de la chaîne empaquetée, avant tout, avant de vous dire quel est le délimiteur. Une telle abstraction serait regroupée en tant que concept, dans la plupart des langues en tant que classe; par exemple, pour que son utilisation soit pratiquement auto-documentée, vous pouvez rechercher tous les endroits où cette classe est utilisée et vous assurer de l'intention du programmeur concernant le format des chaînes compactées dans chaque cas d'utilisation d'une abstraction.

Une fois qu'une telle abstraction est fourni, il serait facile d'utiliser sans avoir à consulter quelle est la valeur du DELIMITERou COLONest, et, en changeant les détails de mise en œuvre serait généralement limitée à la mise en œuvre. En bref, ces constantes devraient être des détails d’application cachés dans une abstraction appropriée.

Le principal attrait de l'utilisation des constantes est qu'elles minimisent la maintenance lorsqu'un changement est nécessaire.

Les bonnes abstractions, qui sont généralement des compositions de plusieurs capacités associées, permettent de minimiser la maintenance. Premièrement, ils séparent clairement le fournisseur des consommateurs. Deuxièmement, ils cachent les détails de la mise en œuvre et fournissent plutôt des fonctionnalités directement utiles. Troisièmement, ils documentent à un niveau élevé quand et où ils sont utilisés.

Erik Eidt
la source
2

La seule fois où j'ai vu de telles constantes utilisées efficacement est de faire correspondre une API ou un document existant. J'ai vu des symboles tels COMMAqu'utilisés, car un logiciel en particulier était directement connecté à un analyseur syntaxique utilisé COMMAcomme une balise dans un arbre de syntaxe abstraite. Je l'ai également vu utilisé pour correspondre à une spécification formelle. dans les spécifications formelles, vous verrez parfois des symboles comme COMMAplutôt que ','parce qu'ils veulent être aussi clairs que possible.

Dans les deux cas, l'utilisation d'un symbole nommé comme COMMAaide à fournir une cohésion à un produit par ailleurs disjoint. Cette valeur peut souvent compenser le coût des notes trop verbeuses.

Cort Ammon
la source
2

Observez que vous essayez de faire une liste.

Donc, refactor comme: String makeList(String[] items)

En d'autres termes, excluez la logique au lieu des données .
Les langues peuvent être différentes dans la façon dont elles représentent les listes, mais les virgules sont toujours des virgules (c'est une tautologie). Donc, si la langue change, changer le caractère de virgule ne vous aidera pas - mais cela vous aidera.

Mehrdad
la source
0

S'il s'agissait d'un cours écrit dans le cadre d'une application de votre collègue développeur, il s'agit certainement d'une mauvaise idée. Comme d'autres l'ont déjà souligné, il est logique de définir des constantes telles que SEPARATOR = ','vous pouvez modifier la valeur et que la constante a toujours un sens, mais beaucoup moins les constantes dont le nom décrit uniquement leur valeur.

Cependant, dans au moins deux cas, il est judicieux de déclarer des constantes dont le nom décrit exactement leur contenu et dans lesquelles vous ne pouvez pas modifier la valeur sans modifier correctement le nom de la constante:

  • Constantes mathématiques ou physiques, par exemple PI = 3.14159. Ici, le rôle de la constante est d'agir comme mnémonique puisque le nom symbolique PIest beaucoup plus court et plus lisible que la valeur qu'il représente.
  • Listes exhaustives de symboles dans un analyseur syntaxique ou de touches d'un clavier. Il peut même être judicieux d’avoir une liste de constantes avec la plupart ou tous les caractères Unicode et c’est là que votre cas risque de tomber. Certains caractères Asont évidents et clairement reconnaissables. Mais pouvez-vous facilement distinguer Аet à Apart? La première est la lettre cyrillique А tandis que le second est la lettre latine A . Ce sont des lettres différentes, représentées par différents points de code Unicode, même si elles sont presque identiques graphiquement. Je préfère avoir des constantes CYRILLIC_CAPITAL_AetLATIN_CAPITAL_Adans mon code que deux caractères presque identiques. Bien entendu, cela est inutile si vous savez que vous ne travaillerez qu'avec des caractères ASCII qui ne contiennent pas de cyrillique. De même: j'utilise l'alphabet latin au quotidien, donc si j'écrivais un programme qui nécessitait un caractère chinois, je préférerais probablement utiliser une constante plutôt que d'insérer un caractère que je ne comprends pas. Au quotidien, les caractères chinois sont évidents, mais les caractères latins peuvent être plus faciles à représenter en tant que constante nommée. Donc, comme vous le voyez, cela dépend du contexte. Néanmoins, une bibliothèque peut contenir des constantes symboliques pour tous les caractères car les auteurs ne peuvent pas savoir à l'avance comment la bibliothèque sera utilisée et quels caractères peuvent nécessiter des constantes pour améliorer la lisibilité dans une application spécifique.

Cependant, de tels cas sont généralement traités par des classes système ou des bibliothèques spéciales et leur occurrence dans du code écrit par les développeurs d'applications devrait être très rare, sauf si vous travaillez sur un projet très spécial.

Michał Kosmulski
la source
-1

Peut être.

Les constantes à un caractère sont relativement difficiles à distinguer. Donc, il peut être assez facile de rater le fait que vous ajoutez un point plutôt qu'une virgule

city + '.' + state

alors que c'est une erreur relativement difficile à faire avec

city + Const.PERIOD + state

En fonction de votre environnement d’internationalisation et de mondialisation, la différence entre une apostrophe ASCII et une apostrophe d’ouverture et de fermeture Windows-1252 (ou entre la double citation ASCII et la citation double d’ouverture et de fermeture Windows-1252) peut être importante et est notoirement difficile à visualiser. au code.

Maintenant, vraisemblablement, si mettre par erreur un point plutôt qu'une virgule était un problème fonctionnel important, vous auriez un test automatisé pour trouver la faute de frappe. Si votre logiciel génère des fichiers CSV, je m'attendrais à ce que votre suite de tests découvre assez rapidement que vous avez eu une période de décalage entre la ville et l'état. Si votre logiciel est supposé fonctionner pour des clients avec une variété de configurations d'internationalisation, votre suite de tests s'exécutera probablement dans chaque environnement et prendra la relève si vous avez un devis ouvert Microsoft si vous vouliez avoir une apostrophe.

Je pourrais imaginer un projet où il serait plus logique d'opter pour un code plus détaillé qui pourrait éviter ces problèmes, en particulier si vous avez un code plus ancien qui n'a pas de suite de tests complète, même si je ne codifierais probablement pas de cette façon. un projet de développement de champs verts. Et l'ajout d'une constante pour chaque caractère de ponctuation plutôt que pour ceux qui sont potentiellement problématiques dans votre application particulière est probablement une surcharge excessive.

Justin Cave
la source
2
que se passe-t-il quand certains débiles changent Const.PERIODpour être égaux ~? Il n'y a aucune justification pour une tautologie de caractères nommés, cela ajoute simplement une maintenance et une complexité qui ne sont plus nécessaires dans les environnements de programmation modernes. Allez-vous écrire une suite de tests unitaires qui dit fondamentalement assert(Const.PERIOD == '.')?
3
@ JarrodRoberson - Ce serait nul, bien sûr. Mais vous auriez tout autant de problèmes si quelqu'un ajoutait une constante Unicode qui ressemblait presque à une virgule plutôt qu'à une virgule réelle. Comme je l'ai dit, ce n'est pas le genre de chose que je ferais dans un projet de développement en arrière-plan. Mais si vous avez une base de code héritée avec une suite de tests inégale dans laquelle vous avez trébuché sur les problèmes posés par une virgule / période ou une apostrophe / abomination Microsoft, créer quelques constantes et inviter les utilisateurs à les utiliser peut être un moyen raisonnable de créer des constantes. le code mieux sans passer une année à écrire des tests.
Justin Cave
3
Votre exemple est un exemple médiocre. Je viens de terminer la refactorisation d’une base de plus de 1 000 000 de codes LOC datant de 18 ans. Chaque caractère imprimable a été défini ainsi plusieurs fois, avec même des noms en conflit. Et souvent, les choses nommées COMMAont été définies = SPACE + "," + SPACE. Oui, un idiot avait une SPACEconstante. Je les ai refacturés TOUT et le code était plus lisible que les ordres de magitude et les recrues des collèges étaient beaucoup plus capables de dépister et de les réparer sans avoir 6 niveaux d’indirection pour savoir ce qui était réellement réglé.
-1

Les constantes à un caractère sont-elles meilleures que les littéraux?

Il y a beaucoup de conflits flottant ici. Laissez-moi voir si je peux les taquiner.

Les constantes fournissent:

  • sémantique
  • changement, pendant le développement
  • indirection

Le fait de descendre à un seul nom de personnage n’affecte que la sémantique. Un nom devrait être utile en tant que commentaire et clair dans son contexte. Il devrait exprimer le sens, pas la valeur. Si on peut faire tout ça avec un seul caractère bien. Si cela ne peut pas, s'il vous plaît ne le faites pas.

Un littéral et une constante peuvent tous deux changer au cours du développement. C'est ce qui soulève la question du nombre magique. Les chaînes peuvent aussi être des nombres magiques.

Si la signification sémantique existe et que les deux sont constants, le fait que la constante ait plus de valeur qu'un littéral revient à indirection.

L’indirection peut résoudre n’importe quel problème, si ce n’est trop indirectionnel.

L'indirection peut résoudre le problème du nombre magique, car il vous permet de choisir une valeur pour une idée à un endroit. Sémantiquement, pour que cela vaille la peine, le nom doit préciser ce que cette idée est claire. Le nom devrait être sur l'idée, pas la valeur.

L'indirection peut être exagérée. Certains préfèrent chercher et remplacer des littéraux pour apporter leurs modifications. C'est bien tant que 42 est clairement le sens de la vie et n'est pas mélangé avec 42, le numéro atomique de molybdène.

Où que vous puissiez faire des distinctions utiles comme cela avec une seule lettre dépend en grande partie du contexte. Mais je n'en ferais pas une habitude.

confits_orange
la source
1
La sémantique est la clé. Si et "A" a plus de sémantique que d'être simplement un "A", alors il vaut la peine de lier la même sémantique à la même "référence". Peu importe si c'est une constante ou non. Je suis entièrement d'accord.
oopexpert
-1

En tant que contrapunctus philosophique de l’opinion majoritaire, je dois dire que certains d’entre nous apprécient le programmeur paysan français du 19ème siècle, peu sophistiqué, et

se rappelait sa lucidité éternelle et monotone, ses vues stupéfiantes de tout, son contentement colossal de truismes simplement parce qu'ils étaient vrais. "Confondre tout!" s'écria Turnbull, "s'il est à l'asile, il ne peut y avoir personne à l'extérieur."

GK Chesterton, le bal et la croix

Il n'y a rien de mal à apprécier la vérité et il n'y a rien de mal à énoncer la vérité, en particulier lorsque vous parlez à un ordinateur.

Si vous mentez à l’ordinateur, vous obtiendrez

Perry Farrar - Germantown, Maryland (tiré de More Programming Pearls)


Mais pour l’essentiel, je suis d’accord avec les gens qui disent que c’est idiot. Je suis trop jeune pour avoir appris à programmer FORTRAN, mais j'ai entendu dire que vous pouviez redéfinir 'A' = 'Q'et créer toutes sortes de cryptogrammes merveilleux. Tu ne fais pas ça.

Au-delà des problèmes de i18n évoqués précédemment (qui ne redéfinissent pas le glyphe "COMMA", mais véritablement le glyphe d'un DECIMAL_POINT). Construire des citations françaises à la carotte ou des citations simples britanniques pour donner un sens aux humains est une chose en soi et celles-ci doivent être des variables et non des constantes. La constante serait AMERICAN_COMMA := ','et lecomma := AMERICAN_COMMA

Et, si j’utilisais un modèle de générateur pour construire une requête SQL, je préférerais de loin voir

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

que toute autre chose, mais si vous alliez ajouter des constantes, ce serait

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)

Cependant, si vous avez déjà regardé un programme (ou un type) de quelqu'un d'autre, vous remarquerez peut-être quelques bizarreries intéressantes. Nous ne sommes pas tous des dactylographes stellaires. Beaucoup d' entre nous ont pour la programmation en retard ou ont été élevés avec des claviers soviétiques (où taper sur vous clés) et nous aimons couper et coller des lettres individuelles au lieu d'essayer de les trouver sur le clavier et / ou se fonder sur autocomplete.

Rien ne va automatiquement compléter une chaîne pour vous, donc si je peux obtenir une virgule en appuyant sur 'con', alt-espace, bas, bas, bas, entrez et obtenez une citation en appuyant sur 'con', alt-espace, bas, bas, entrez. Je pourrais juste faire ça.


Une autre chose à retenir sur les littéraux de chaîne est la façon dont ils sont compilés. Dans Delphi au moins (qui est le seul langage que j'ai obsédé par la pile), vous allez finir vos littéraux apparus dans la pile de chaque fonction. Donc, beaucoup de littéraux = beaucoup de temps système; "," dans function_A n’est pas le même bit de mémoire qu’un "," dans function_B ". Pour lutter contre cela, il existe une" chaîne de ressources "qui peut être construite et liée latéralement - et c’est comme cela qu’ils font. En Python, tous vos littéraux de chaîne sont des objets, et cela peut sembler agréable à utiliser utils.constants.COMMA.join(["some","happy","array","strings"]), mais ce n’est pas une idée géniale pour les points répétés maintes et maintes fois sur cette page.

Peter Turner
la source
-4

Mais quand allons-nous commencer à utiliser un symbole différent de "," pour représenter une virgule?

Pour la localisation.

Dans les pays anglophones, le symbole séparant les parties entière et décimale d’une décimale est ".", Que nous appelons "point décimal". Dans de nombreux autres pays, le symbole est "," et est généralement appelé l'équivalent de "virgule" dans la langue locale. De même, lorsque les pays anglophones utilisent "," pour séparer des groupes de trois chiffres en grand nombre (par exemple, 1 000 000 sur un million), les pays qui utilisent une virgule comme virgule décimale utilisent un point (1 000 000).

Il est donc judicieux de créer des constantes DECIMAL_POINT et COMMA si vous effectuez une globalisation.

Paul G
la source
2
Mais alors, COMMA et DECIMAL_POINT ne sont pas les noms corrects pour les entités (ce qui explique probablement pourquoi vous avez été voté à la baisse).
Kyle Strand
Vous devrez compiler des versions spécifiques localisées. Les constantes littérales ne conviennent pas à cela; ce cas d'utilisation appelle des fichiers de définition et des recherches dans ceux-ci (ce qui peut impliquer des constantes, mais des constantes de recherche, pas des caractères constants).