Pourquoi les noms de variables ne peuvent-ils pas commencer par des nombres?

136

Je travaillais avec un nouveau développeur C ++ il y a quelque temps lorsqu'il a posé la question: "Pourquoi les noms de variables ne peuvent-ils pas commencer par des nombres?"

Je n'ai pas pu trouver de réponse, sauf que certains nombres peuvent contenir du texte (123456L, 123456U) et cela ne serait pas possible si les compilateurs pensaient que tout avec une certaine quantité de caractères alpha était un nom de variable.

Était-ce la bonne réponse? Y a-t-il d'autres raisons?

string 2BeOrNot2Be = "that is the question"; // Why won't this compile?
Jérémie
la source
15
Et pourquoi ne peuvent-ils pas y avoir d'espaces?
Tim
4
Ce problème est antérieur au C ++ d'au moins 20 ans, sinon aux premiers assembleurs de macros.
Ken Gentle
2
Eh bien, dans FORTH, vous pouvez le faire. AFAIK, il y a un mot appelé 0qui pousse 0 sur la pile. un autre est 0=qui vérifie si 0 est sur la pile.
Ingo
12
Pourquoi cette question est-elle si populaire et les réponses si fausses? De nombreux langages permettent aux variables de commencer par des nombres. C ++ ne le fait pas mais c'est juste une limitation pratique qui évite certaines ambiguïtés. Parfois, SO m'étonne de toutes les mauvaises manières.
david.pfx
5
Si cette question a été posée aujourd'hui sur SO, elle sera qualifiée d'opinion et clôturée. Merci d'avoir posé cette question.
Boon

Réponses:

116

Parce qu'alors une chaîne de chiffres serait un identifiant valide ainsi qu'un nombre valide.

int 17 = 497;
int 42 = 6 * 9;
String 1111 = "Totally text";
sauter
la source
37
Eh bien, que se passerait-il s'ils disaient que les variables ne peuvent pas être uniquement des nombres. Alors quoi?
Pyrolistique
6
Il me faudrait plus de temps pour trouver une expression régulière pour que le lexeur récupère les identifiants en utilisant cette règle, si c'est même possible, donc je peux voir pourquoi aucun langage n'a jamais été implémenté de cette façon, en plus des raisons données dans d'autres réponses.
skiphoppy
39
S'il devait s'agir de nombres + alpha, vous pouvez toujours faire String 0x123 = "Hello World". À moins que vous n'indiquiez que les noms de variables sont des "nombres + alpha qui n'analysent pas une désignation numérique valide", et c'est juste idiot.
eaolson
4
Peu importe le compilateur: les personnes utilisant le langage doivent pouvoir distinguer facilement (d'un coup d'œil) les noms de variables des nombres. Si le premier caractère ne vous disait pas - au lieu de cela, si vous aviez besoin de chercher dans le reste du mot pour savoir s'il y avait un alpha non numérique quelque part - le code serait plus difficile à lire.
comingstorm
10
@eaolson: J'ai travaillé avec un assembleur qui a appliqué cette règle aux nombres hexadécimaux commençant par A- Fet se terminant par h. Cela m'a fait trébucher la première fois que j'ai essayé de définir un label pour pointer vers les données musicales de la Two Part Invention # 13 de Bach (nom logique? Bach).
supercat
116

Pensez-y bien:

int 2d = 42;
double a = 2d;

Qu'est-ce qu'un? 2.0? ou 42?

Astuce, si vous ne comprenez pas, d après un nombre signifie le nombre avant qu'il ne soit un double littéral

Pyrolistique
la source
11
Il s'agit en fait d'une notation à venir [relativement] tardive ("d" pour "double"), norme C89 IIRC. Les chiffres de tête dans les identificateurs ne sont pas possibles si cette construction est dans le langage, mais ce n'est pas la raison pour laquelle les nombres ne peuvent pas démarrer un identificateur.
Ken Gentle
1
dn'est pas un suffixe littéral flottant valide en C ++. Les littéraux flottants sont des doubles par défaut, vous pouvez utiliser fou lsi vous avez besoin d'un float ou d'un long double littéral.
CB Bailey
1
C'est pour Java, et bien que la question d'origine était pour C ++, elle s'applique également à de nombreux autres langages, comme Java. Mais je suis d'accord. Ce n'est pas la raison pour laquelle les identifiants ne peuvent pas commencer par des chiffres.
Pyrolistique
50

C'est une convention maintenant, mais cela a commencé comme une exigence technique.

Autrefois, les parseurs de langages tels que FORTRAN ou BASIC ne nécessitaient pas l'utilisation d'espaces. Donc, fondamentalement, les éléments suivants sont identiques:

10 V1=100
20 PRINT V1

et

10V1=100
20PRINTV1

Supposons maintenant que les préfixes numériques soient autorisés. Comment interpréteriez-vous cela?

101V=100

comme

10 1V = 100

ou comme

101 V = 100

ou comme

1 01V = 100

Donc, cela a été rendu illégal.

Roy Dictus
la source
1
Nit mineur: les numéros de ligne devaient figurer dans les colonnes 1 à 6 et le code exécutable après la colonne 8. D'un autre côté, il DO 10 I=1,50pourrait être analysé de manière ambiguë comme DO1 0I=1,50[d'ailleurs, si l'on utilise un point au lieu d'une virgule, l'instruction devient une affectation à un variable à virgule flottante nommée DO10I.
supercat
Explication intéressante! Cela a du sens pour les langages plus anciens, je me demande encore pourquoi nous avons continué le choix de conception pour des langages comme Python ou JavaScript ou R.
Charles Clayton
Je m'en souviens vraiment avec BASIC et je pense que c'est probablement la raison pratique la plus valable de la pratique. Techniquement cependant, je me souviens vaguement qu'il peut en fait revenir au premier langage d'assemblage. Je ne suis pas sûr de savoir quel assembleur, et je pourrais très bien me tromper.
Brian Chandler
42

Parce que le retour en arrière est évité dans l'analyse lexicale lors de la compilation. Une variable comme:

Apple;

le compilateur saura tout de suite qu'il s'agit d'un identifiant lorsqu'il rencontre la lettre «A».

Cependant une variable comme:

123apple;

Le compilateur ne pourra pas décider s'il s'agit d'un nombre ou d'un identifiant jusqu'à ce qu'il atteigne «a», et il a donc besoin d'un retour en arrière.

Jiayang
la source
2
Pour répondre en se souvenant de ma classe de conception de compilateur, cette réponse va tout droit! Kudos
nehem
15

Compilateurs / analyseurs / analyseurs lexicaux était pour moi il y a très, très longtemps, mais je pense que je me souviens qu'il était difficile de déterminer sans ambiguïté si un caractère numérique dans l'unité de compilation représentait un littéral ou un identifiant.

Les langues où l'espace est insignifiant (comme ALGOL et le FORTRAN d'origine si je me souviens bien) ne pouvaient pas accepter les nombres pour commencer les identificateurs pour cette raison.

Cela remonte à loin - avant les notations spéciales pour désigner le stockage ou la base numérique.

Ken Gentle
la source
9

Je conviens qu'il serait pratique de permettre aux identifiants de commencer par un chiffre. Une ou deux personnes ont mentionné que vous pouvez contourner cette restriction en ajoutant un trait de soulignement à votre identifiant, mais c'est vraiment moche.

Je pense qu'une partie du problème vient des nombres littéraux tels que 0xdeadbeef, qui rendent difficile l'élaboration de règles faciles à retenir pour les identificateurs qui peuvent commencer par un chiffre. Une façon de faire pourrait être d'autoriser tout ce qui correspond à [A-Za-z _] + qui n'est PAS un mot-clé ou un littéral numérique. Le problème est que cela conduirait à autoriser des choses étranges comme 0xdeadpork, mais pas 0xdeadbeef. En fin de compte, je pense que nous devrions être justes envers toutes les viandes: P.

Quand j'ai appris le C pour la première fois, je me souviens avoir senti que les règles pour les noms de variables étaient arbitraires et restrictives. Pire encore, ils étaient difficiles à retenir, alors j'ai renoncé à essayer de les apprendre. J'ai juste fait ce qui me semblait juste, et cela a plutôt bien fonctionné. Maintenant que j'ai appris beaucoup plus, cela ne semble pas si mal, et j'ai finalement réussi à l'apprendre correctement.

allyourcode
la source
8
LOL - "Le problème est que cela conduirait à autoriser des choses étranges comme 0xdeadpork, mais pas 0xdeadbeef. En fin de compte, je pense que nous devrions être justes envers toutes les viandes: P."
mr-euro
6

C'est probablement une décision qui est venue pour plusieurs raisons, lorsque vous analysez le jeton, vous n'avez qu'à regarder le premier caractère pour déterminer s'il s'agit d'un identifiant ou d'un littéral, puis de l'envoyer à la fonction appropriée pour le traitement. C'est donc une optimisation des performances.

L'autre option serait de vérifier si ce n'est pas un littéral et de laisser le domaine des identifiants comme l'univers moins les littéraux. Mais pour ce faire, vous devrez examiner chaque caractère de chaque jeton pour savoir comment le classer.

Il y a aussi les implications stylistiques que les identificateurs sont censés être des mnémoniques, donc les mots sont beaucoup plus faciles à retenir que les nombres. Quand beaucoup de langues originales étaient écrites, définissant les styles pour les prochaines décennies, ils ne pensaient pas à remplacer «2» par «à».

William
la source
6

Les noms de variables ne peuvent pas commencer par un chiffre, car cela peut causer des problèmes comme ci-dessous:

int a = 2;
int 2 = 5;
int c = 2 * a; 

quelle est la valeur de c? vaut 4 ou 10!

un autre exemple:

float 5 = 25;
float b = 5.5;

est le premier 5 un nombre, ou est un objet (opérateur.) Il y a un problème similaire avec le second 5.

Peut-être, il y a d'autres raisons. Donc, nous ne devons utiliser aucun chiffre au début d'un nom de variable.

sbagdat
la source
Même si l'on exigeait que les identificateurs contiennent au moins un caractère non numérique, il faudrait également exiger que les formats numériques contenant des lettres contiennent également un caractère non alphanumérique [par exemple, il faut que 0x1234 soit écrit comme $ 1234 et 1E6 soit écrit comme 1.E6 ou 1.0E6] ou bien avoir une combinaison étrange de noms d'identificateurs légaux et illégaux.
supercat le
4

L'utilisation d'un chiffre pour commencer un nom de variable rend la vérification des erreurs lors de la compilation ou de l'interpertation beaucoup plus compliquée.

Autoriser l'utilisation de noms de variables commençant par un nombre poserait probablement d'énormes problèmes aux concepteurs de langage. Lors de l'analyse du code source, chaque fois qu'un compilateur / interpréteur rencontrait un jeton commençant par un chiffre où un nom de variable était attendu, il devrait rechercher dans un ensemble de règles énorme et compliqué pour déterminer si le jeton était vraiment une variable ou une erreur . La complexité supplémentaire ajoutée à l'analyseur de langage peut ne pas justifier cette fonctionnalité.

Aussi loin que je me souvienne (environ 40 ans), je ne pense pas avoir jamais utilisé un langage qui permettait d'utiliser un chiffre pour commencer les noms de variables. Je suis sûr que cela a été fait au moins une fois. Peut-être que quelqu'un ici a vu ça quelque part.

mkClark
la source
1
Ce n'est pas si difficile. Cela rend la phase lexicale plus difficile, c'est tout. Bien sûr, lorsque j'ai pris des compilateurs, on m'a dit que l'analyse lexicale pouvait prendre plus d'un quart du temps total de compilation.
David Thornley
4

Comme plusieurs personnes l'ont remarqué, il y a beaucoup de bagages historiques sur les formats valides pour les noms de variables. Et les concepteurs de langage sont toujours influencés par ce qu'ils savent lorsqu'ils créent de nouveaux langages.

Cela dit, à peu près tout le temps, un langage ne permet pas aux noms de variables de commencer par des nombres parce que ce sont les règles de la conception du langage. Souvent, c'est parce qu'une règle aussi simple facilite l'analyse et le lexing du langage. Cependant, tous les concepteurs de langage ne savent pas que c'est la vraie raison. Les outils de lexing modernes sont utiles, car si vous avez essayé de le définir comme autorisé, ils vous donneront une analyse des conflits.

OTOH, si votre langue a un caractère identifiable de manière unique pour annoncer les noms de variables, il est possible de le configurer pour qu'ils commencent par un nombre. Des variantes de règles similaires peuvent également être utilisées pour autoriser des espaces dans les noms de variables. Mais le langage qui en résulte ne ressemblera probablement pas beaucoup à un langage conventionnel populaire, voire pas du tout.

Pour un exemple de langage de création de modèles HTML assez simple qui permet aux variables de commencer par des nombres et d'avoir des espaces incorporés, regardez Qompose .

statique
la source
1
En fait, il existe plusieurs langues qui vous permettent d'avoir des caractères marquant des identifiants. Ils sont appelés "sigils" et vous les avez en Perl et PHP.
Jason Baker
Sauf que vous n'êtes toujours pas autorisé à commencer un nom de variable en PHP par un nombre - les règles de langage l'interdisent. :-) Mais vous pouvez dans Qompose pour exactement la même raison.
statique
4

Parce que si vous permettiez au mot-clé et à l'identifiant de commencer par des caractères numériques, le lexer (qui fait partie du compilateur) ne pouvait pas facilement différencier le début d'un littéral numérique et d'un mot-clé sans devenir beaucoup plus compliqué (et plus lent).

Nicolas Carey
la source
2
Le processus de lexing est rarement le goulot d'étranglement. Bien sûr, cela rend l'expression régulière des jetons d'identification plus complexe, mais ils peuvent toujours être des DFA ultra-rapides. Le runtime de ceux-ci est des cacahuètes par rapport à la plupart des autres tâches que les compilateurs doivent accomplir.
4

La restriction est arbitraire. Divers Lisps permettent aux noms de symboles de commencer par des chiffres.

Kyle Jones
la source
4

COBOL permet aux variables de commencer par un chiffre.

Brad
la source
2

C ++ ne peut pas l'avoir car les concepteurs de langage en ont fait une règle. Si vous deviez créer votre propre langage, vous pourriez certainement l'autoriser, mais vous rencontreriez probablement les mêmes problèmes qu'eux et décideriez de ne pas l'autoriser. Exemples de noms de variables qui poseraient des problèmes:

0x, 2d, 5555

Kevin
la source
Cette restriction est valable dans les langues où ce type de syntaxe n'est pas autorisé.
Jason Baker
2

L'un des principaux problèmes liés à l'assouplissement des conventions syntaxiques est qu'il introduit une dissonance cognitive dans le processus de codage. La façon dont vous pensez de votre code pourrait être profondément influencée par le manque de clarté que cela introduirait.

N'est-ce pas Dykstra qui a dit que "l'aspect le plus important de tout outil est son effet sur son utilisateur"?

spéléologie
la source
1

Probablement parce que cela permet à l'humain de dire plus facilement s'il s'agit d'un numéro ou d'un identifiant, et à cause de la tradition. Avoir des identifiants qui pourraient commencer par un chiffre ne compliquerait pas tant les analyses lexicales.

Toutes les langues n'ont pas d'identificateurs interdits commençant par un chiffre. Dans Forth, ils pouvaient être des nombres, et les petits entiers étaient normalement définis comme des mots Forth (essentiellement des identificateurs), car il était plus rapide de lire "2" comme une routine pour pousser un 2 sur la pile que de reconnaître "2" comme un nombre dont la valeur était 2. (Lors du traitement de l'entrée du programmeur ou du bloc de disque, le système Forth divisait l'entrée en fonction d'espaces. Il essaierait de chercher le jeton dans le dictionnaire pour voir s'il s'agissait d'un mot défini, et sinon, il essaierait de le traduire en nombre, et sinon signalerait une erreur.)

David Thornley
la source
Le fait est que Forth n'a pas vraiment d'analyseur très sophistiqué. Vraiment, tout ce qui compte, c'est si un identifiant se trouve entre deux ensembles d'espaces.
Jason Baker
1

Supposons que vous ayez autorisé les noms de symboles à commencer par des nombres. Supposons maintenant que vous souhaitiez nommer une variable 12345foobar. Comment différencieriez-vous cela de 12345? Ce n'est en fait pas très difficile à faire avec une expression régulière. Le problème est en fait un problème de performance. Je ne peux pas vraiment expliquer pourquoi c'est très détaillé, mais cela se résume essentiellement au fait que la différenciation de 12345foobar de 12345 nécessite un retour en arrière. Cela rend l'expression régulière non déterministe.

Il y a une bien meilleure explication à cela ici .

Jason Baker
la source
1
Comment concevoir une expression régulière pour autoriser une variable nommée ifqou doublezmais pas ifou double? Le problème fondamental de permettre aux identificateurs de commencer par des chiffres serait qu'il existe des formes existantes de littéraux hexadécimaux et de nombres à virgule flottante qui se composent entièrement de caractères alphanumériques (les langues utiliseraient quelque chose comme $ 1234 ou h'1234 au lieu de 0x1234, et nécessiteraient des nombres comme 1E23 pour inclure un point, pourrait éviter ce problème). Notez que les tentatives d'analyse de regex C peuvent déjà être déclenchées par des choses comme 0x12E+5.
supercat
1

il est facile pour un compilateur d'identifier une variable en utilisant ASCII sur l'emplacement mémoire plutôt que sur le nombre.

Vivek
la source
1

Le compilateur a 7 phases comme suit:

  1. Analyse lexicale
  2. Analyse de la syntaxe
  3. Analyse sémantique
  4. Génération de code intermédiaire
  5. Optimisation du code
  6. Génération de code
  7. Table des symboles

Le backtracking est évité dans la phase d'analyse lexicale lors de la compilation du morceau de code. La variable comme Apple, le compilateur connaîtra son identifiant tout de suite quand il rencontrera la lettre «A» dans la phase d'analyse lexicale. Cependant, une variable comme 123apple, le compilateur ne pourra pas décider si c'est un nombre ou un identifiant jusqu'à ce qu'il atteigne 'a' et il a besoin de revenir en arrière pour passer dans la phase d'analyse lexicale pour identifier qu'il s'agit d'une variable. Mais il n'est pas pris en charge dans le compilateur.

Lorsque vous analysez le jeton, il vous suffit de regarder le premier caractère pour déterminer s'il s'agit d'un identificateur ou d'un littéral, puis de l'envoyer à la fonction appropriée pour le traitement. C'est donc une optimisation des performances.

Harikesh
la source
0

Je pense que la réponse simple est que c'est possible, la restriction est basée sur la langue. En C ++ et bien d'autres, ce n'est pas possible car le langage ne le prend pas en charge. Cela ne fait pas partie des règles.

La question revient à demander pourquoi le roi ne peut-il pas déplacer quatre cases à la fois dans les échecs? C'est parce qu'aux échecs, c'est un coup illégal. Peut-il dans un autre jeu sûr. Cela dépend simplement des règles jouées.

kemiller2002
la source
Sauf que le C ++ a été inventé récemment par des personnes encore en vie. Nous pouvons leur demander pourquoi ils ont choisi les choses qu'ils ont faites et ont rejeté les alternatives. La même chose ne s'applique pas aux échecs.
Steve Jessop
Mais ce n'est pas ce que je veux dire. C'est une analogie avec la raison pour laquelle il ne peut pas y avoir de nombres au début des noms de variables, et la réponse la plus simple est que les règles du langage ne le permettent pas.
kemiller2002
Bien sûr, mais je ne pense pas que le questionneur soit un imbécile. Il a probablement déjà travaillé jusque-là tout seul. La question de l'OMI est "pourquoi les règles de la langue ne le permettent-elles pas?". Il veut combler le fossé entre la connaissance des règles et leur compréhension.
Steve Jessop
Ouais, en réfléchissant à ça, j'ai réalisé où tu allais. Vous avez un point. Je suppose que j'appliquais un peu le rasoir d'Occam librement et supposais qu'il n'y avait pas de vraie réponse à la raison, sauf que les variables ne commencent pas par des nombres, car il n'y a pas de nombres.
kemiller2002
Je ne dis pas que vous vous trompez, esprit, parfois les décisions des organismes de normalisation C ++ dépassent la compréhension mortelle, et vous vous retrouvez avec "parce qu'ils ont dû décider quelque chose et ils ont décidé cela". Mais il y a au moins une question à poser :-)
Steve Jessop
0

À l'origine, c'était simplement parce qu'il est plus facile de se souvenir (vous pouvez lui donner plus de sens) des noms de variables sous forme de chaînes plutôt que de nombres bien que des nombres puissent être inclus dans la chaîne pour améliorer la signification de la chaîne ou permettre l'utilisation du même nom de variable mais faites-le désigner comme ayant un sens ou un contexte séparé mais proche. Par exemple, loop1, loop2, etc. vous feraient toujours savoir que vous étiez dans une boucle et / ou que la boucle 2 était une boucle dans loop1. Laquelle préférez-vous (a plus de sens) comme variable: adresse ou 1121298? Qu'est-ce qui est plus facile à retenir? Cependant, si le langage utilise quelque chose pour indiquer qu'il ne s'agit pas seulement de texte ou de nombres (comme le $ in $ address), cela ne devrait vraiment pas faire de différence car cela indiquerait au compilateur que ce qui suit doit être traité comme une variable ( dans ce cas).

cjtech
la source
0

La variable peut être considérée comme une valeur également pendant la compilation par le compilateur afin que la valeur puisse appeler la valeur encore et encore de manière récursive

Aravinthe
la source
0

Le backtracking est évité en phase d'analyse lexicale lors de la compilation du morceau de code . La variable comme Apple; , le compilateur connaîtra son identifiant tout de suite lorsqu'il rencontrera le caractère de lettre «A» dans la phase d'analyse lexicale. Cependant, une variable comme 123apple; , le compilateur ne pourra pas décider s'il s'agit d'un numéro ou d'un identifiant jusqu'à ce qu'il atteigne «a» et qu'il ait besoin d'un retour en arrière pour passer dans la phase d'analyse lexicale pour identifier qu'il s'agit d'une variable. Mais il n'est pas pris en charge dans le compilateur.

Référence

Angelin Nadar
la source
0

Il ne pourrait y avoir rien de mal à cela lorsqu'il s'agit de déclarer une variable, mais il y a une certaine ambiguïté quand il essaie d'utiliser cette variable ailleurs comme ceci:

let 1 = "Bonjour tout le monde!" imprimer (1) imprimer (1)

print est une méthode générique qui accepte tous les types de variables. donc dans cette situation, le compilateur ne sait pas à quel (1) le programmeur se réfère: le 1 d'une valeur entière ou le 1 qui stocke une valeur de chaîne. peut-être mieux pour le compilateur dans cette situation de permettre de définir quelque chose comme ça, mais lorsque vous essayez d'utiliser ce truc ambigu, apportez une erreur avec une capacité de correction pour savoir comment corriger cette erreur et effacer cette ambiguïté.

Ali Torabi
la source