¿Por qué los nombres de variables no pueden comenzar con números?

136

Estaba trabajando con un nuevo desarrollador de C ++ hace un tiempo cuando me hizo la pregunta: "¿Por qué los nombres de variables no pueden comenzar con números?"

No pude encontrar una respuesta, excepto que algunos números pueden tener texto (123456L, 123456U) y eso no sería posible si los compiladores estuvieran pensando que todo con cierta cantidad de caracteres alfabéticos es un nombre variable.

¿Era esa la respuesta correcta? ¿Hay más razones?

string 2BeOrNot2Be = "that is the question"; // Why won't this compile?
Jeremías
fuente
15
¿Y por qué no pueden tener espacios en ellos?
Tim
44
Este problema es anterior a C ++ por al menos 20 años, si no vuelve a los primeros macro ensambladores.
Ken Gentle
2
Bueno, en FORTH, puedes hacerlo. AFAIK, hay una palabra llamada 0que empuja 0 a la pila. otro es 0=que verifica si 0 está en la pila.
Ingo
12
¿Por qué esta pregunta es tan popular y las respuestas tan incorrectas? Muchos idiomas permiten que las variables comiencen con números. C ++ no lo hace, pero es solo una limitación conveniente que evita ciertas ambigüedades. A veces SO me sorprende de todas las maneras equivocadas.
david.pfx
55
Si esta pregunta se hizo hoy en SO, se denominará basada en opinión y cierre. Gracias por preguntar esto.
Boon

Respuestas:

116

Porque entonces una cadena de dígitos sería un identificador válido, así como un número válido.

int 17 = 497;
int 42 = 6 * 9;
String 1111 = "Totally text";
skiphoppy
fuente
37
Bueno, ¿y si dicen que las variables no pueden ser solo números? ¿Y que?
Pirolítico
66
Me tomaría más tiempo encontrar una expresión regular para que el lexer recoja identificadores usando esa regla, si es posible, por lo que puedo ver por qué ningún idioma se ha implementado de esa manera, además de las razones dadas en Otras respuestas.
skiphoppy
39
Si tuviera que ser números + alfa, aún podría hacer String 0x123 = "Hello World". A menos que indique que los nombres de las variables son "números + alfa que no se analizan con una designación numérica válida", y eso es una tontería.
eaolson
44
No importa el compilador: las personas que usan el lenguaje deben poder distinguir fácilmente (de un vistazo) los nombres de las variables de los números. Si el primer carácter no le dijera, en su lugar, si necesitara buscar en el resto de la palabra para saber si había un alfa no numérico en algún lugar, el código sería más difícil de leer.
Próxima tormenta
10
@eaolson: He trabajado con un ensamblador que aplicó esa regla a los números hexadecimales que comenzaron con A- Fy terminaron con h. Me tropecé la primera vez que intenté definir una etiqueta para señalar los datos musicales de la Invención n. ° 13 de Bach (¿nombre lógico? Bach).
supercat
116

Bueno, piensa en esto:

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

¿Qué es un? 2.0? o 42?

Sugerencia, si no lo obtiene, d después de un número significa el número antes de que sea un doble literal

Pirolista
fuente
11
Esta es en realidad una notación [relativamente] tardía ("d" para "doble"), estándar C89 IIRC. Los números iniciales en los identificadores no son posibles si esta construcción está en el lenguaje, pero esa no es la razón por la que los números no pueden iniciar un identificador.
Ken Gentle
1
dno es un sufijo literal flotante válido en C ++. Los literales flotantes son dobles por defecto, puede usar fo lsi necesita un flotante o un doble literal largo.
CB Bailey
1
Es para Java, y aunque la pregunta original era para C ++, también se aplica a muchos otros lenguajes, como Java. Pero estoy de acuerdo. Esta no es la razón original por la cual los identificadores no pueden comenzar con números.
Pirolítico
50

Es una convención ahora, pero comenzó como un requisito técnico.

En los viejos tiempos, los analizadores de idiomas como FORTRAN o BASIC no requerían el uso de espacios. Entonces, básicamente, los siguientes son idénticos:

10 V1=100
20 PRINT V1

y

10V1=100
20PRINTV1

Ahora suponga que se permiten prefijos numéricos. ¿Cómo interpretarías esto?

101V=100

como

10 1V = 100

o como

101 V = 100

o como

1 01V = 100

Entonces, esto se hizo ilegal.

Roy Dictus
fuente
1
Min menor: los números de línea tenían que estar en las columnas 1-6, y el código ejecutable después de la columna 8. Por otro lado, DO 10 I=1,50podría analizarse de manera ambigua como DO1 0I=1,50[incidentalmente, si uno usa un punto en lugar de una coma, la declaración se convierte en una asignación a un variable de punto flotante llamada DO10I.
supercat
Interesante explicación! Eso tiene sentido para los idiomas más antiguos, todavía me hace preguntarme por qué seguimos con la elección del diseño para lenguajes como Python o JavaScript o R.
Charles Clayton
Definitivamente recuerdo esto con BASIC y siento que esta es probablemente la razón práctica más válida de la práctica. Sin embargo, técnicamente, recuerdo vagamente que en realidad puede volver al lenguaje ensamblador temprano. Sin embargo, no estoy seguro de qué ensamblador, y muy bien podría estar equivocado.
Brian Chandler
42

Porque se evita el retroceso en el análisis léxico durante la compilación. Una variable como:

Apple;

el compilador sabrá que es un identificador de inmediato cuando se encuentre con la letra 'A'.

Sin embargo, una variable como:

123apple;

el compilador no podrá decidir si es un número o identificador hasta que toque 'a', y como resultado necesita retroceder.

Jiayang
fuente
2
Para responder recordando mi clase de diseños de compiladores, ¡esta respuesta va directamente a la derecha! Felicitaciones
nehem
15

Los compiladores / analizadores / analizadores léxicos fue hace mucho, mucho tiempo para mí, pero creo recordar que hubo dificultades para determinar sin ambigüedades si un carácter numérico en la unidad de compilación representaba un literal o un identificador.

Los idiomas donde el espacio es insignificante (como ALGOL y el FORTRAN original si no recuerdo mal) no pudieron aceptar números para comenzar identificadores por esa razón.

Esto se remonta, antes de las anotaciones especiales para denotar almacenamiento o base numérica.

Ken Gentle
fuente
9

Estoy de acuerdo en que sería útil permitir que los identificadores comiencen con un dígito. Una o dos personas han mencionado que puede sortear esta restricción anteponiendo un guión bajo a su identificador, pero eso es realmente feo.

Creo que parte del problema proviene de literales numéricos como 0xdeadbeef, que dificultan encontrar reglas fáciles de recordar para identificadores que pueden comenzar con un dígito. Una forma de hacerlo podría ser permitir cualquier cosa que coincida con [A-Za-z _] + que NO sea una palabra clave o un número literal. El problema es que llevaría a cosas extrañas como 0xdeadpork permitido, pero no 0xdeadbeef. En última instancia, creo que deberíamos ser justos con todas las carnes: P.

Cuando estaba aprendiendo C por primera vez, recuerdo sentir que las reglas para los nombres de variables eran arbitrarias y restrictivas. Lo peor de todo, eran difíciles de recordar, así que dejé de tratar de aprenderlos. Simplemente hice lo que me pareció bien y funcionó bastante bien. Ahora que he aprendido mucho más, no parece tan malo, y finalmente pude aprenderlo bien.

allyourcode
fuente
8
LOL - "El problema es que llevaría a cosas extrañas como 0xdeadpork permitido, pero no 0xdeadbeef. En última instancia, creo que deberíamos ser justos con todas las carnes: P".
Sr.-euro
6

Es probable que se haya tomado una decisión por varias razones, cuando analiza el token solo tiene que mirar el primer carácter para determinar si es un identificador o literal y luego enviarlo a la función correcta para su procesamiento. Entonces esa es una optimización de rendimiento.

La otra opción sería verificar si no es un literal y dejar que el dominio de los identificadores sea el universo menos los literales. Pero para hacer esto, tendría que examinar cada carácter de cada ficha para saber cómo clasificarlo.

También existe la implicación estilística que se supone que los identificadores son mnemónicos, por lo que las palabras son mucho más fáciles de recordar que los números. Cuando se escribieron muchos de los idiomas originales estableciendo los estilos para las próximas décadas, no estaban pensando en sustituir "2" por "a".

Guillermo
fuente
6

Los nombres de las variables no pueden comenzar con un dígito, porque puede causar algunos problemas, como a continuación:

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

¿Cuál es el valor de c? es 4 o es 10!

otro ejemplo:

float 5 = 25;
float b = 5.5;

es el primer 5 un número, o es un objeto (operador.) Hay un problema similar con el segundo 5.

Tal vez, hay algunas otras razones. Por lo tanto, no debemos usar ningún dígito al comienzo de un nombre de variable.

sbagdat
fuente
Incluso si se requiere que los identificadores contengan al menos un carácter que no sea un dígito, también se debería requerir que los formatos numéricos que contienen letras también contengan un carácter no alfanumérico [por ejemplo, se requiere que 0x1234 se escriba como $ 1234 y se escriba 1E6 para ser escrito como 1.E6 o 1.0E6] o bien tienen una combinación extraña de nombres de identificadores legales e ilegales.
supercat
4

El uso de un dígito para comenzar un nombre de variable hace que la verificación de errores durante la compilación o la interacción sea mucho más complicada.

Permitir el uso de nombres de variables que comenzaron como un número probablemente causaría grandes problemas a los diseñadores de idiomas. Durante el análisis del código fuente, cada vez que un compilador / intérprete encuentra un token que comienza con un dígito donde se esperaba un nombre de variable, tendría que buscar a través de un conjunto enorme y complicado de reglas para determinar si el token era realmente una variable o un error . La complejidad añadida al analizador de idiomas puede no justificar esta característica.

Hasta donde puedo recordar (alrededor de 40 años), no creo que alguna vez haya usado un lenguaje que permitiera el uso de un dígito para comenzar nombres variables. Estoy seguro de que esto se hizo al menos una vez. Tal vez, alguien aquí ha visto esto en alguna parte.

mkClark
fuente
1
No es tan dificil. Hace que la fase léxica sea más difícil, eso es todo. Por supuesto, cuando tomé compiladores, me dijeron que el escaneo léxico podría tomar más de una cuarta parte del tiempo total de compilación.
David Thornley
4

Como varias personas han notado, hay mucho bagaje histórico sobre formatos válidos para nombres de variables. Y los diseñadores de idiomas siempre están influenciados por lo que saben cuando crean nuevos idiomas.

Dicho esto, casi todo el tiempo un idioma no permite que los nombres de variables comiencen con números es porque esas son las reglas del diseño del lenguaje. A menudo se debe a que una regla tan simple hace que el análisis del lenguaje sea mucho más fácil. Sin embargo, no todos los diseñadores de idiomas saben que esta es la verdadera razón. Las herramientas de lexing modernas ayudan, porque si tratas de definirlo como permisible, te darán conflictos de análisis.

OTOH, si su idioma tiene un carácter identificable para anunciar nombres de variables, es posible configurarlo para que comiencen con un número. También se pueden usar variaciones de reglas similares para permitir espacios en nombres de variables. Pero es probable que el lenguaje resultante no se parezca mucho a ningún lenguaje convencional popular, si es que lo hace.

Para ver un ejemplo de un lenguaje de plantillas HTML bastante simple que permite que las variables comiencen con números y tengan espacios incrustados, consulte Qompose .

staticsan
fuente
1
En realidad, hay varios idiomas que le permiten tener caracteres que marcan identificadores. Se llaman "sigilos" y los tienes en Perl y PHP.
Jason Baker
Excepto que todavía no puedes comenzar un nombre de variable en PHP con un número; las reglas del lenguaje lo prohíben. :-) Pero puedes en Qompose exactamente por la misma razón.
staticsan
4

Porque si permitía que la palabra clave y el identificador comenzaran con caracteres numéricos, el lexer (parte del compilador) no podría diferenciar fácilmente entre el inicio de un literal numérico y una palabra clave sin volverse mucho más complicado (y más lento).

Nicholas Carey
fuente
2
El proceso de lexing rara vez es el cuello de botella. Claro, hace que la expresión regular para los tokens de identificación sea más compleja, pero aún pueden ser DFA súper rápidos. El tiempo de ejecución de esos son los cacahuetes en comparación con la mayoría de las otras tareas que los compiladores tienen que cumplir.
4

La restricción es arbitraria. Varios Lisps permiten que los nombres de los símbolos comiencen con números.

Kyle Jones
fuente
4

COBOL permite que las variables comiencen con un dígito.

puntilla
fuente
2

C ++ no puede tenerlo porque los diseñadores de lenguaje lo convirtieron en una regla. Si creara su propio idioma, ciertamente podría permitirlo, pero probablemente se encontraría con los mismos problemas que ellos y decidiría no permitirlo. Ejemplos de nombres de variables que causarían problemas:

0x, 2d, 5555

Kevin
fuente
Sin embargo, esta restricción se aplica en idiomas donde ese tipo de sintaxis no está permitida.
Jason Baker
2

Uno de los problemas clave sobre las convenciones sintácticas relajantes es que introduce disonancia cognitiva en el proceso de codificación. La forma en que piensa sobre su código podría verse profundamente influenciada por la falta de claridad que esto introduciría.

¿No fue Dykstra quien dijo que "el aspecto más importante de cualquier herramienta es su efecto en el usuario"?

espeleología
fuente
1

Probablemente porque hace que sea más fácil para el humano saber si es un número o un identificador, y por tradición. Tener identificadores que podrían comenzar con un dígito no complicaría demasiado los escaneos léxicos.

No todos los idiomas tienen identificadores prohibidos que comienzan con un dígito. En Forth, podrían ser números, y los enteros pequeños normalmente se definían como palabras Forth (esencialmente identificadores), ya que era más rápido leer "2" como una rutina para empujar un 2 en la pila que reconocer "2" como un número cuyo valor era 2. (Al procesar la entrada del programador o del bloque de disco, el sistema Forth dividiría la entrada de acuerdo con los espacios. Intentaría buscar el token en el diccionario para ver si era una palabra definida, y si no, intentaría traducirlo a un número, y si no, marcaría un error).

David Thornley
fuente
La cuestión es que Forth realmente no tiene un analizador muy sofisticado. Realmente, lo único que le importa es si un identificador está entre dos conjuntos de espacios en blanco.
Jason Baker
1

Supongamos que permitiste que los nombres de los símbolos comenzaran con números. Ahora suponga que desea nombrar una variable 12345foobar. ¿Cómo diferenciarías esto de 12345? En realidad no es terriblemente difícil de hacer con una expresión regular. El problema es en realidad uno de rendimiento. Realmente no puedo explicar por qué esto es con gran detalle, pero esencialmente se reduce al hecho de que diferenciar 12345foobar de 12345 requiere retroceder. Esto hace que la expresión regular no sea determinista.

Hay una explicación mucho mejor de esto aquí .

Jason Baker
fuente
1
¿Cómo diseñaría una expresión regular para permitir una variable llamada ifqo doublezpero no ifo double? El problema fundamental al permitir que los identificadores comiencen con dígitos sería que existen formas existentes de literales hexadecimales y números de punto flotante que consisten completamente en caracteres alfanuméricos (los idiomas usarían algo como $ 1234 o h'1234 en lugar de 0x1234, y requieren números como 1E23 para incluir un período, podría evitar ese problema). Tenga en cuenta que los intentos de análisis de expresiones regulares C ya pueden ser disparados por cosas como 0x12E+5.
supercat
1

es fácil para un compilador identificar una variable usando ASCII en la ubicación de la memoria en lugar de un número.

Vivek
fuente
1

El compilador tiene 7 fases de la siguiente manera:

  1. Análisis léxico
  2. Análisis de sintaxis
  3. Análisis semántico
  4. Generación de código intermedio
  5. Optimización de código
  6. Codigo de GENERACION
  7. Tabla de símbolos

Se evita el retroceso en la fase de análisis léxico al compilar el fragmento de código. La variable como Apple, el compilador sabrá que es un identificador de inmediato cuando se encuentre con el carácter de letra 'A' en la fase de análisis léxico. Sin embargo, una variable como 123apple, el compilador no podrá decidir si es un número o identificador hasta que toque 'a' y necesite retroceder para pasar a la fase de análisis léxico para identificar que es una variable. Pero no es compatible con el compilador.

Cuando analiza el token, solo tiene que mirar el primer carácter para determinar si es un identificador o literal y luego enviarlo a la función correcta para su procesamiento. Entonces esa es una optimización de rendimiento.

Harikesh
fuente
0

Creo que la respuesta simple es que puede, la restricción está basada en el lenguaje. En C ++ y muchos otros no puede porque el lenguaje no lo admite. No está integrado en las reglas para permitir eso.

La pregunta es similar a preguntar por qué el Rey no puede moverse cuatro espacios a la vez en Ajedrez. Es porque en el ajedrez es un movimiento ilegal. Puede en otro juego seguro. Solo depende de las reglas que se están jugando.

kemiller2002
fuente
Excepto que C ++ fue inventado recientemente por personas que todavía están vivas. Podemos preguntarles por qué eligieron las cosas que hicieron y rechazaron las alternativas. Lo mismo no se aplica al ajedrez.
Steve Jessop
Pero ese no es el punto que estoy haciendo. Es una analogía de por qué no puede haber números al comienzo de los nombres de variables, y la respuesta más simple es, porque las reglas del lenguaje no lo permiten.
kemiller2002
Claro, pero no creo que el interrogador sea un imbécil. Probablemente ya haya llegado tan lejos solo. La pregunta de la OMI es "¿por qué las reglas del lenguaje no lo permiten?". Quiere cerrar la brecha entre conocer las reglas y comprenderlas.
Steve Jessop
Sí, al reflexionar sobre esto, me di cuenta de a dónde ibas. Usted tiene un punto. Supongo que estaba aplicando la navaja de Occam un poco libremente y asumí que no hay una respuesta real a por qué, excepto que las variables no comienzan con números, porque no hay números.
kemiller2002
No digo que estés equivocado, recuerda, ocasionalmente las decisiones de los organismos de estándares de C ++ superan la comprensión mortal, y terminas con "porque tuvieron que decidir algo y decidieron esto". Pero hay al menos una pregunta que hacer :-)
Steve Jessop
0

Originalmente era simplemente porque es más fácil recordar (puede darle más significado) nombres de variables como cadenas en lugar de números, aunque los números se pueden incluir dentro de la cadena para mejorar el significado de la cadena o permitir el uso del mismo nombre de variable, pero haga que se designe como un significado o contexto separado pero cercano. Por ejemplo, loop1, loop2, etc., siempre le permitirán saber que estaba en un loop y / o que el loop 2 era un loop dentro de loop1. ¿Cuál preferiría (tiene más significado) como variable: dirección o 1121298? ¿Cuál es más fácil de recordar? Sin embargo, si el lenguaje usa algo para denotar que no es solo texto o números (como la dirección $ en $), realmente no debería hacer una diferencia, ya que eso le diría al compilador que lo que sigue debe ser tratado como una variable ( en este caso).

cjtech
fuente
0

El compilador puede considerar la variable como un valor también durante el tiempo de compilación, por lo que el valor puede llamar al valor una y otra vez de forma recursiva

aravinth
fuente
0

Se evita el retroceso en la fase de análisis léxico al compilar el fragmento de código . La variable como Apple; , el compilador sabrá que es un identificador de inmediato cuando se encuentre con el carácter de letra 'A' en la fase de Análisis léxico. Sin embargo, una variable como 123apple; , el compilador no podrá decidir si es un número o un identificador hasta que toque 'a' y necesite retroceder para pasar a la fase de análisis léxico para identificar que es una variable. Pero no es compatible con el compilador.

Referencia

Angelin Nadar
fuente
0

No puede haber nada de malo cuando se trata de declarar la variable, pero hay cierta ambigüedad cuando se trata de usar esa variable en otro lugar como este:

let 1 = "¡Hola mundo!" imprimir (1) imprimir (1)

print es un método genérico que acepta todos los tipos de variables. entonces, en esa situación, el compilador no sabe a qué (1) se refiere el programador: el 1 de valor entero o el 1 que almacena un valor de cadena. tal vez sea mejor para el compilador que en esta situación permita definir algo así, pero cuando intente usar estas cosas ambiguas, traiga un error con capacidad de corrección sobre cómo solucionar ese error y eliminar esta ambigüedad.

Ali Torabi
fuente