Por que nomes de variáveis ​​não podem começar com números?


136

Eu estava trabalhando com um novo desenvolvedor de C ++ há algum tempo quando ele fez a pergunta: "Por que nomes de variáveis ​​não podem começar com números?"

Não consegui encontrar uma resposta, exceto que alguns números podem conter texto (123456L, 123456U) e isso não seria possível se os compiladores estivessem pensando que tudo com alguma quantidade de caracteres alfa era um nome variável.

Essa foi a resposta certa? Existem mais razões?

string 2BeOrNot2Be = "that is the question"; // Why won't this compile?

15
E por que eles não podem ter espaços neles?
Tim

4
Esse problema antecede o C ++ por pelo menos 20 anos, se não voltar aos primeiros montadores de macro.
Ken Gentle

2
Bem, em FORTH, você pode fazê-lo. AFAIK, existe uma palavra chamada 0que empurra 0 para a pilha. outro é 0=que verifica se 0 está na pilha.
Ingo

12
Por que essa pergunta é tão popular e as respostas tão erradas? Muitos idiomas permitem que variáveis ​​iniciem com números. C ++ não, mas é apenas uma limitação conveniente que evita certas ambiguidades. Às vezes SO me surpreende de todas as maneiras erradas.
David.pfx

5
Se esta pergunta foi feita hoje no SO, será denominada baseada em opinião e encerrada. Obrigado por perguntar isso.
Boon

Respostas:


116

Porque então uma sequência de dígitos seria um identificador válido e também um número válido.

int 17 = 497;
int 42 = 6 * 9;
String 1111 = "Totally text";

37
Bem, e se eles dissessem que variáveis ​​não podem ser apenas números. Então o que?
Pyrolistical

6
Levaria mais tempo para criar uma expressão regular para o lexer pegar identificadores usando essa regra, se for possível, para que eu possa ver por que nenhuma linguagem foi implementada dessa maneira, além dos motivos apresentados em outras respostas.
Skiphoppy

39
Se tivesse que ser números + alfa, você ainda poderia fazer String 0x123 = "Hello World". A menos que você indique que os nomes de variáveis ​​são "números + alfa que não analisam uma designação numérica válida", e isso é bobagem.
Eaolson 11/10/09

4
Não importa o compilador: as pessoas que usam o idioma precisam ser capazes de distinguir prontamente (rapidamente) nomes de variáveis ​​de números. Se o primeiro caractere não disser a você - em vez disso, se você precisar pesquisar o restante da palavra para saber se havia um alfa não numérico em algum lugar - o código seria mais difícil de ler.
comingstorm 18/06/12

10
@eaolson: Eu trabalhei com um assembler que aplicava essa regra aos números hexadecimais que começavam com A- Fe terminavam com h. Tropecei na primeira vez em que tentei definir um rótulo para apontar para os dados da música da Invenção 13 de Bach em duas partes (nome lógico? Bach).
Supercat #

116

Bem, pense sobre isso:

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

O que é uma? 2.0? ou 42?

Dica, se você não conseguir, d depois de um número significa o número antes que seja um literal duplo


11
Esta é realmente uma notação [relativamente] tardia ("d" para "dupla"), padrão C89 IIRC. Os números numéricos iniciais nos identificadores não são possíveis se essa construção estiver no idioma, mas esse não é o motivo pelo qual os números não podem iniciar um identificador.
Ken Gentle

1
dnão é um sufixo literal flutuante válido em C ++. Literais flutuantes são duplos por padrão, você pode usar fou lse precisar de um flutuante ou um longo duplo literal.
CB Bailey

1
É para Java e, embora a pergunta original fosse para C ++, também se aplica a muitas outras linguagens, como Java. Mas eu concordo. Esta não é a razão original pela qual os identificadores não podem começar com números.
Pyrolistical 04/04/2008

50

É uma convenção agora, mas começou como um requisito técnico.

Antigamente, analisadores de idiomas como FORTRAN ou BASIC não exigiam o uso de espaços. Então, basicamente, o seguinte é idêntico:

10 V1=100
20 PRINT V1

e

10V1=100
20PRINTV1

Agora, suponha que prefixos numéricos sejam permitidos. Como você interpretaria isso?

101V=100

Como

10 1V = 100

ou como

101 V = 100

ou como

1 01V = 100

Então, isso foi feito ilegal.


1
Nit menor: os números de linha devem estar nas colunas 1-6 e o ​​código executável após a coluna 8. Por outro lado, DO 10 I=1,50pode ser analisado ambiguamente como DO1 0I=1,50[aliás, se alguém usar um ponto em vez de vírgula, a instrução se tornará uma atribuição a um variável de ponto flutuante denominada DO10I.
Supercat #

Explicação interessante! Isso faz sentido para as línguas mais antigas, ainda faz-me pergunto por que ainda tenho continuado a escolha de design para linguagens como Python ou JavaScript ou R.
Charles Clayton

Eu definitivamente me lembro disso com o BASIC e sinto que essa é provavelmente a razão prática mais válida da prática. Tecnicamente, porém, lembro-me vagamente de que ela pode realmente voltar à linguagem assembly inicial. Não tenho certeza do que montador, porém, e posso muito bem estar errado.
Brian Chandler

42

Porque o retorno é evitado na análise lexical durante a compilação. Uma variável como:

Apple;

o compilador saberá que é um identificador imediatamente quando encontrar a letra 'A'.

No entanto, uma variável como:

123apple;

O compilador não será capaz de decidir se é um número ou identificador até atingir 'a' e, portanto, precisa voltar atrás.


2
Para responder, lembrando-me da minha classe de projetos de compilador, esta resposta vai direto para a direita! Kudos
nehem

15

Os compiladores / analisadores / analisadores lexicais foram muito, muito tempo atrás para mim, mas acho que me lembro de haver dificuldade em determinar sem ambigüidade se um caractere numérico na unidade de compilação representava um literal ou um identificador.

Idiomas em que o espaço é insignificante (como ALGOL e FORTRAN original, se bem me lembro) não podiam aceitar números para iniciar identificadores por esse motivo.

Isso remonta - antes de notações especiais para indicar armazenamento ou base numérica.


9

Concordo que seria útil permitir que os identificadores começassem com um dígito. Uma ou duas pessoas mencionaram que você pode contornar essa restrição acrescentando um sublinhado ao seu identificador, mas isso é realmente feio.

Acho que parte do problema vem de literais numéricos como 0xdeadbeef, que dificultam a criação de regras fáceis de lembrar para identificadores que podem começar com um dígito. Uma maneira de fazer isso pode ser permitir qualquer coisa que corresponda a [A-Za-z _] + que NÃO seja uma palavra-chave ou literal de número. O problema é que isso levaria a coisas estranhas como 0xdeadpork, mas não 0xdeadbeef. Por fim, acho que devemos ser justos com todas as carnes: p.

Quando aprendi C pela primeira vez, lembro que as regras para nomes de variáveis ​​eram arbitrárias e restritivas. Pior de tudo, eles eram difíceis de lembrar, então desisti de tentar aprendê-los. Eu apenas fiz o que parecia certo, e funcionou muito bem. Agora que aprendi muito mais, não parece tão ruim e finalmente aprendi direito.


8
LOL - "O problema é que isso levaria a coisas estranhas como o porco 0xdead, mas não o 0xdeadbeef. Por fim, acho que devemos ser justos com todas as carnes: P".
mr-euro

6

É provável que tenha sido uma decisão tomada por alguns motivos: quando você estiver analisando o token, precisará analisar apenas o primeiro caractere para determinar se é um identificador ou literal e enviá-lo para a função correta para processamento. Então, isso é uma otimização de desempenho.

A outra opção seria verificar se não é um literal e deixar o domínio dos identificadores como o universo menos os literais. Mas para fazer isso, você teria que examinar todos os caracteres de cada token para saber como classificá-lo.

Há também as implicações estilísticas que os identificadores devem ser mnemônicos, de modo que as palavras são muito mais fáceis de lembrar do que números. Quando muitos idiomas originais foram escritos, definindo os estilos para as próximas décadas, eles não estavam pensando em substituir "2" por "para".


6

Os nomes de variáveis ​​não podem começar com um dígito, pois podem causar alguns problemas, como abaixo:

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

qual é o valor de c? é 4 ou é 10!

outro exemplo:

float 5 = 25;
float b = 5.5;

é o primeiro 5 um número ou é um objeto (operador.) Há um problema semelhante com o segundo 5.

Talvez haja outras razões. Portanto, não devemos usar nenhum dígito no início de um nome de variável.


Mesmo se alguém exigisse que os identificadores contenham pelo menos um caractere que não seja um dígito, também seria necessário exigir que os formatos numéricos que contêm letras também contenham um caractere não alfanumérico [por exemplo, exija que 0x1234 seja gravado como $ 1234 e 1E6 para ser gravado como 1.E6 ou 1.0E6] ou então tem uma combinação ímpar de nomes de identificadores legais e ilegais.
precisa

4

O uso de um dígito para iniciar o nome de uma variável torna a verificação de erros durante a compilação ou interoperação muito mais complicada.

Permitir o uso de nomes de variáveis ​​que começaram como um número provavelmente causaria grandes problemas para os designers de idiomas. Durante a análise do código-fonte, sempre que um compilador / intérprete encontrava um token começando com um dígito em que era esperado um nome de variável, ele precisava pesquisar um conjunto enorme e complicado de regras para determinar se o token era realmente uma variável ou um erro . A complexidade adicionada ao analisador de idiomas pode não justificar esse recurso.

Desde que me lembro (cerca de 40 anos), acho que nunca usei uma linguagem que permitisse o uso de um dígito para iniciar nomes de variáveis. Tenho certeza de que isso foi feito pelo menos uma vez. Talvez alguém aqui tenha visto isso em algum lugar.


1
Não é tão difícil assim. Isso torna a fase lexical mais difícil, só isso. É claro que, quando peguei compiladores, me disseram que a digitalização lexical poderia levar mais de um quarto do tempo total de compilação.
David Thornley

4

Como várias pessoas notaram, há muita bagagem histórica sobre formatos válidos para nomes de variáveis. E os designers de idiomas são sempre influenciados pelo que sabem quando criam novos idiomas.

Dito isso, quase sempre o idioma não permite que nomes de variáveis ​​comecem com números, porque essas são as regras do design do idioma. Muitas vezes, é porque uma regra tão simples facilita muito a análise e o lexing do idioma. Nem todos os designers de idiomas sabem que esse é o motivo real. As ferramentas modernas de lexing ajudam, porque se você tentar defini-lo como permitido, elas fornecerão análises de conflitos.

OTOH, se o seu idioma tiver um caractere identificável exclusivamente para anunciar nomes de variáveis, é possível configurá-lo para que eles comecem com um número. Variações de regra semelhantes também podem ser usadas para permitir espaços nos nomes de variáveis. Mas é provável que o idioma resultante não se assemelhe muito a nenhum idioma convencional popular, se é que existe.

Para um exemplo de uma linguagem de modelagem HTML bastante simples que permite que variáveis ​​iniciem com números e tenham espaços incorporados, consulte Qompose .


1
Na verdade, existem vários idiomas que permitem ter caracteres marcando identificadores. Eles são chamados de "sigils" e você os possui em Perl e PHP.
213 Jason Baker

Exceto que você ainda não tem permissão para iniciar um nome de variável no PHP com um número - as regras da linguagem o proíbem. :-) Mas você pode no Qompose exatamente pelo mesmo motivo.
Staticsan 20/05/09

4

Como se você permitisse que a palavra-chave e o identificador começassem com caracteres numéricos, o lexer (parte do compilador) não conseguiria diferenciar facilmente o início de um literal numérico e de uma palavra-chave sem ficar muito mais complicado (e mais lento).


2
O processo de lexing raramente é o gargalo. Claro, isso torna o regex para tokens de identificador mais complexo, mas eles ainda podem ser DFAs super rápidos. O tempo de execução desses é amendoim, comparado à maioria das outras tarefas que os compiladores precisam realizar.

4

A restrição é arbitrária. Vários Lisps permitem que nomes de símbolos comecem com numerais.


4

COBOL permite que variáveis ​​iniciem com um dígito.


2

C ++ não pode tê-lo porque os designers de linguagem fizeram disso uma regra. Se você fosse criar seu próprio idioma, certamente poderia permitir, mas provavelmente enfrentaria os mesmos problemas que eles e decidiria não permitir. Exemplos de nomes de variáveis ​​que causariam problemas:

0x, 2d, 5555


Essa restrição ocorre em idiomas onde esse tipo de sintaxe não é permitido.
Jason Baker

2

Um dos principais problemas para relaxar convenções sintáticas é que ela introduz dissonância cognitiva no processo de codificação. Como você pensa sobre seu código pode ser profundamente influenciado pela falta de clareza que isso introduziria.

Não foi Dykstra quem disse que "o aspecto mais importante de qualquer ferramenta é o seu efeito no usuário"?


1

Provavelmente porque torna mais fácil para o ser humano dizer se é um número ou um identificador e por causa da tradição. Ter identificadores que pudessem começar com um dígito não complicaria muito as verificações lexicais.

Nem todos os idiomas têm identificadores proibidos começando com um dígito. Em Quarto Quarto, eles poderiam ser números, e pequenos números inteiros eram normalmente definidos como Quarto Quarto (essencialmente identificadores), pois era mais rápido ler "2" como uma rotina para inserir um 2 na pilha do que reconhecer "2" como um número. cujo valor era 2. (Ao processar a entrada do programador ou do bloco de disco, o quarto sistema dividiria a entrada de acordo com os espaços. Ele tentaria procurar o token no dicionário para ver se era uma palavra definida e se não, tentaria convertê-lo em um número e, se não, sinalizaria um erro.)


O fato é que Forth realmente não possui um analisador muito sofisticado. Realmente, tudo o que importa é se um identificador está entre dois conjuntos de espaços em branco.
213 Jason Baker

1

Suponha que você permita que os nomes dos símbolos comecem com números. Agora, suponha que você queira nomear uma variável 12345foobar. Como você diferenciaria isso de 12345? Na verdade, não é muito difícil fazer uma expressão regular. O problema é realmente de desempenho. Eu realmente não posso explicar por que isso está em grandes detalhes, mas basicamente se resume ao fato de que diferenciar 12345foobar de 12345 requer retroceder. Isso torna a expressão regular não determinística.

Há uma explicação muito melhor sobre isso aqui .


1
Como alguém projetaria uma expressão regular para permitir uma variável nomeada ifqou doublezmas não ifou double? O problema fundamental de permitir que os identificadores iniciem com dígitos seria que existem formas existentes de literais hexadecimais e números de ponto flutuante que consistem inteiramente em caracteres alfanuméricos (os idiomas usariam algo como $ 1234 ou h'1234 em vez de 0x1234 e exigiriam números como 1E23 para incluir um período, poderia evitar esse problema). Observe que as tentativas de analisar C de regex já podem ser desencadeadas por coisas como 0x12E+5.
Supercat #

1

é fácil para um compilador identificar uma variável usando ASCII na localização da memória e não no número.


1

O compilador possui 7 fases da seguinte maneira:

  1. Análise lexical
  2. Análise de sintaxe
  3. Análise Semântica
  4. Geração intermediária de código
  5. Otimização de código
  6. Geração de código
  7. Tabela de símbolos

O retorno é evitado na fase de análise lexical ao compilar o trecho de código. A variável como Apple, o compilador saberá seu identificador imediatamente quando encontrar o caractere da letra 'A' na fase lexical de análise. No entanto, uma variável como 123apple, o compilador não será capaz de decidir se é um número ou identificador até atingir 'a' e precisa voltar atrás na fase de análise lexical para identificar que é uma variável. Mas isso não é suportado no compilador.

Ao analisar o token, você precisa apenas olhar para o primeiro caractere para determinar se é um identificador ou literal e enviá-lo para a função correta para processamento. Então, isso é uma otimização de desempenho.


0

Eu acho que a resposta simples é que pode, a restrição é baseada na linguagem. No C ++ e em muitos outros, não pode, porque a linguagem não suporta. Não está embutido nas regras para permitir isso.

A pergunta é semelhante a perguntar por que o rei não pode mover quatro espaços por vez no xadrez? É porque no xadrez é uma jogada ilegal. Pode em outro jogo com certeza. Depende apenas das regras que estão sendo jogadas.


Exceto que o C ++ foi inventado recentemente por pessoas que ainda estão vivas. Podemos perguntar-lhes por que escolheram as coisas que fizeram e rejeitaram as alternativas. O mesmo não se aplica ao xadrez.
Steve Jessop

Mas esse não é o ponto que estou afirmando. É uma analogia do porquê de não haver números no início dos nomes de variáveis ​​e a resposta mais simples é porque as regras da linguagem não permitem isso.
precisa saber é o seguinte

Claro, mas não acho que o interlocutor seja um imbecil. Ele provavelmente já trabalhou tão longe sozinho. A questão da IMO é "por que as regras do idioma não permitem?". Ele quer preencher a lacuna entre conhecer as regras e entendê-las.
Steve Jessop

Sim, ao refletir sobre isso, eu percebi para onde você estava indo. Você tem um ponto. Eu acho que eu estava aplicando um pouco a navalha de Occam livremente e assumi que não há resposta real para o porquê, exceto que as variáveis ​​não começam com números, porque não existem números.
kemiller2002

Não estou dizendo que você está errado, às vezes, as decisões dos órgãos dos padrões C ++ superam a compreensão mortal, e você acaba "porque eles tiveram que decidir alguma coisa e decidiram isso". Mas há pelo menos uma questão há de ser perguntado :-)
Steve Jessop

0

Originalmente, era simplesmente porque é mais fácil lembrar (você pode dar mais significado) nomes de variáveis ​​como cadeias, em vez de números, embora os números possam ser incluídos na cadeia para aprimorar o significado da cadeia ou permitir o uso do mesmo nome de variável, mas designá-lo como tendo um significado ou contexto separado, mas próximo. Por exemplo, loop1, loop2 etc sempre informaria que você estava em um loop e / ou o loop 2 era um loop no loop1. Qual você prefere (tem mais significado) como uma variável: endereço ou 1121298? Qual é mais fácil de lembrar? No entanto, se o idioma usar algo para indicar que não é apenas texto ou números (como o endereço $ em $), ele realmente não deve fazer diferença, pois isso diria ao compilador que o que se segue deve ser tratado como uma variável ( nesse caso).


0

A variável pode ser considerada como um valor também durante o tempo de compilação pelo compilador, para que o valor possa chamar o valor novamente e novamente recursivamente


0

O retorno é evitado na fase de análise lexical ao compilar o trecho de código . A variável como Apple; , o compilador saberá seu identificador imediatamente quando encontrar o caractere da letra 'A' na fase de análise lexical. No entanto, uma variável como 123apple; , o compilador não poderá decidir se é um número ou identificador até que ele atinja 'a' e precise voltar atrás na fase de análise lexical para identificar se é uma variável. Mas isso não é suportado no compilador.

Referência


0

Não pode haver nada de errado com isso quando se declara variável. Mas há alguma ambiguidade quando tenta usar essa variável em outro lugar como este:

deixe 1 = "Olá mundo!" impressão (1) impressão (1)

print é um método genérico que aceita todos os tipos de variáveis. portanto, nessa situação, o compilador não sabe a qual (1) o programador se refere: o 1 do valor inteiro ou o 1 que armazena um valor de string. talvez seja melhor para o compilador nessa situação permitir definir algo assim, mas ao tentar usar esse material ambíguo, traga um erro com capacidade de correção para como corrigir esse erro e limpar essa ambiguidade.

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.