Most programming languages appear to be designed to not allow one to declare an identifier that starts with a number. I was just curious to know the reason. I have already searched the web, but couldn't find a satisfactory explanation.
In C/C++, a number followed by a letter is considered to be a numeric constant and the string that follows, qualifies the type of the constant. So for example (these are VC++, not sure how standard they are):
- 0 - signed integer
- 0l - signed long integer
- 0u - unsigned integer
- 0i64 - 64 bit signed integer
So a) it is easier for the lexer as Daniel said but also b) it makes an explicit distinction since 0y might be a variable but 0u would never be. Plus other qualifiers, like "i64" were added way later than "l" or "u" and they want to keep the option open of adding more if needed.
Consider the following 2 cases:
Lets assume that an identifier could begin with a number.
So a statement like below would be valid (since an identifier can have 1 or more characters) :
When I try to use the above variable in a program, it'll result in compiler ambiguity:
In the statement
a=3 what is the role of 3 (is it a variable with value 5 or is it the numeral 3) ?
As opposed to the example above, lets assume that a language were to actually allow identifiers starting with a number while still disallowing numerals being used as identifiers. This can cause the following issues:
The language rules regarding the variable which says that a variable can consist of 1 or more characters will have to be redefined to a complex rule like: A variable can have one or more characters and must be unique if it does not start with a number while it cannot be of single character length when starting with a number (etc..)
The compiler will have to check for and report error cases when all numerals (eg 333) and valid alphabet suffixes (e.g. 34L) are being used as variable names. In loosely typed languages like Python and JS where you can use variables on the fly without declaring them, it may even be impossible to check for the special cases involving all numerals e.g.
if (33==5)Here, 33 could be an erroneous undeclared variable that the user has declared. But the compiler will not be able to identify this and report the error.
Making this restriction will prevent the programmer from using numbers as identifier names.
For the most part this has nothing to do with making it easy for the compiler writers and parsing efficiency, but, more to do with designing a syntax that encourages clear readable and unambiguous code.
Its the language designers thought it would be nice to be able to write numeric literals like the number 1 as just plain 1 .
It would be quite possible to design a language syntax where numeric literals were quoted in some way for example tildas so the numberic literal for number one was encoded as ~1~ and anything not a keyword and not enclosed in quotes was treated as a variable name.
So you could code statements like:
1 = ~2~ two = 1 * ~2~
2 = ~3~ six = 2 + 2
Whatever syntax you choose ambiguous and hard to follow code is unavoidable.
The C language and most of the "curly brackets" languages descended from C also thought it a good idea to allow programmers to code Octal and Hexadecimal literals directly, and, to specify the type of the literal if this was important. So
010 // Octal 10 = 8; 0x10 // Hexadecimal 10 = 16; 5l // long integer with decimal value 5 2.0d // double float with value 2
So even if you allowed variable names start with a number followed by a combination of numbers and letter that included at least one letter you would present the programmer with the problem of deciding whether a given group formed a variable name or a numeric literal so
2lll = 22 // OK 2ll = 2 // compiler error
Such ambiguity would not help anyone writing or reading a program.
For a closely related real world example you could look at PL/1 language whose designers thought that being able to use keywords as variable names was a good idea so that:
IF THEN THEN THEN = ELSE; ELSE ELSE = THEN; IF IF THEN ELSE = IF; ELSE THEN = ELSE; DO WHILE (WHILE = DO); END = WHILE + DO; END;
Is valid code which compiles and executes.
Fortran had a huge effect on how later languages were designed. Early on (some of these problems have since been fixed) Fortran had almost no rules restricting what name you could give to an identifier. This made the language extremely difficult to parse both for compilers and for programmers. Here's one classic example:
if if .eq. then then = else else else = endif endif K I K K I I K I I K
Here I've marked the "language key words" with K and the identifiers (variable names) I. Given that there's no difference in spelling, I think you can probably understand how confusing this could be. Of course, this is an extreme example, and it's unlikely anybody ever wrote code quite like this on purpose. Sometimes people did "recycle" language key words as identifier names though -- and in a lot of cases a simple typo could result in code that the language spec said should be parsed this way, even though it wasn't intended at all. For another well-known example, compare this:
do 10 i = 1,10
do 10 i = 1.10
The first is a do loop -- iterating a block of code 10 times. The second, however, has had the comma changed to a decimal point, so it's assigning the value
1.10 to a variable named
do 10 i.
This also meant that writing a Fortran parser was relatively difficult -- you couldn't be certain that the
do at the beginning of the line was really a key word until you reached the end of the line, and verified that all the other elements of a
do loop were present. The parser generally had to be ready to "backtrack", re-parsing the line from the beginning to come to the "correct" (but often unintended) answer of what was really there.
After a few years of this, language designers (most of them anyway) went toward the opposite extreme -- restricting nearly everything about the language as much as possible without the users complaining too much.
Early BASIC, for example, basically said you couldn't even use a key word as part of an identifier -- for example,
fora=1 would be parsed as
for a = 1 (i.e., the beginning of a
for loop, not an assignment). That apparently generated enough complaints that it didn't last very long. The rule about starting an identifier with a digit apparently hasn't generated a lot of complaints, so it continues to be used (at least in most languages).
Likely this convention has evolved from very early historical language design decisions, as on early machines the entire compiler, including lexical analysis, had to run in a few kWords, less memory than even just the first-level processor data cache on current mobile devices, so the allowed variable names were very limited, and had to be easy to distinguish from numeric constants in very few op codes.
Thus, the convention became what generations of programmers are used to.
It's not a logically required rule for programming language but just the convention used by many language designers.
I can design radically different language that allow all character for identifiers. For all code lines, first 20 character will describe the statement type then next 20 character will define the first symbol for the statement, and next 20 character is operand for the statement. This language will be executed on a stack processor.
01234567890123456789 01234567890123456789 01234567890123456789 decl symbol 12345 assign value 12345 12345 decl symbol 99999 assign value 99999 12345 push 12345 push 99999 add print top
This code could be translated in C as below:
int i12345 = 12345; int i99999 = 12345; printf("%d", i12345+i9999);
That's all. It's meaningless and the no-number-in-identifiers rule is also pointless in logical ground.
In addition to "convenience for the lexer", I think it is also worth considering "convenience for the reader".
When reading code, you need to quickly and repeatedly identify which words are identifiers, and which are numbers. Looking for a digit at the beginning is easier on our visual pattern-matching; it would be a chore if we had to carefully check all the characters to make sure.
The answer to this question lies in automata or more precisely finite automata that defines the regular expression. The rule is...compilers need exact algorithms or rules to decide at every character that they parse. If identifiers were allowee to start with a number then the compiler will be in a fix..about the nature of the token coming...will it be a number or an identifier...and as compilers cant backtrack to earlier positions...so..to make it clear to the compiler that the coming token is precisely an identifier or a number...this restriction is there...coz of this...compiler knows just by scanning the first character that the coming token is an identifier or a number.