Почему имена переменных не могут начинаться с цифр?


136

Некоторое время назад я работал с новым разработчиком C ++, когда он задал вопрос: «Почему имена переменных не могут начинаться с цифр?»

Я не мог придумать ответ, за исключением того, что некоторые числа могут содержать текст (123456L, 123456U), и это было бы невозможно, если бы компиляторы думали, что все с некоторым количеством буквенных символов является именем переменной.

Это был правильный ответ? Есть еще причины?

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

15
И почему в них не может быть пробелов?
Тим

4
Эта проблема предшествует C ++ по крайней мере на 20 лет, если не вернуться к первым макросам.
Кен Джентл,

2
Что ж, в FORTH это можно сделать. AFAIK, есть слово, 0которое помещает 0 в стек. другой - 0=проверяет, находится ли в стеке 0.
Ingo

12
Почему этот вопрос так популярен, а ответы так неверны? Во многих языках переменные могут начинаться с цифр. C ++ не делает, но это просто удобное ограничение, которое позволяет избежать определенных двусмысленностей. Иногда ТАК меня поражает неправильным образом.
david.pfx

5
Если этот вопрос был задан сегодня на SO, он будет называться основанным на мнении и закрытым. Спасибо, что спросили об этом.
Boon

Ответы:


116

Потому что тогда строка цифр будет как действительным идентификатором, так и действительным числом.

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

37
Что, если бы они сказали, что переменные не могут быть только числами. Тогда что?
Pyrolistical

6
Мне потребовалось бы больше времени, чтобы придумать регулярное выражение для лексера, чтобы подбирать идентификаторы с использованием этого правила, если это вообще возможно, поэтому я могу понять, почему ни один язык никогда не был реализован таким образом, в дополнение к причинам, указанным в другие ответы.
skiphoppy

39
Если бы это были числа + альфа, вы все равно могли бы сделать String 0x123 = "Hello World". Если вы не укажете, что имена переменных - это «числа + альфа, которые не соответствуют действительному числовому обозначению», и это просто глупо.
eaolson,

4
Не обращайте внимания на компилятор: люди, использующие язык, должны уметь легко (с первого взгляда) отличать имена переменных от чисел. Если бы первый символ не сказал вам - вместо этого, если бы вам нужно было перебрать остальную часть слова, чтобы определить, есть ли где-то нечисловая буква - код будет труднее читать.
приближающаяся буря

10
@eaolson: я работал с ассемблером, который применял это правило к шестнадцатеричным числам, которые начинались с A- Fи заканчивались h. Подстегнул меня в первый раз, когда я попытался определить лейбл, указывающий на музыкальные данные для изобретения Баха из двух частей № 13 (логическое имя? Bach).
supercat

116

Хорошо подумайте об этом:

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

Что такое? 2,0? или 42?

Подсказка: если вы не поняли, d после числа означает, что число перед ним является двойным литералом


11
На самом деле это [относительно] позднее появившаяся нотация ("d" для "двойного"), стандарт IIRC C89. Ведущие числа в идентификаторах невозможны, если эта конструкция написана на языке, но это не причина, по которой числа не могут начинать идентификатор.
Кен Джентл,

1
dне является допустимым плавающим литеральным суффиксом в C ++. Плавающие литералы по умолчанию являются двойными , вы можете использовать fили, lесли вам нужен плавающий или длинный двойной литерал.
CB Bailey

1
Это для Java, и хотя исходный вопрос был для C ++, он также применим ко многим другим языкам, таким как Java. Но я согласен. Это не основная причина, по которой идентификаторы не могут начинаться с цифр.
Pyrolistical

50

Сейчас это соглашение, но началось оно как техническое требование.

Раньше парсеры таких языков, как FORTRAN или BASIC не требовали использования пробелов. Итак, в основном следующие идентичны:

10 V1=100
20 PRINT V1

и

10V1=100
20PRINTV1

Теперь предположим, что числовые префиксы разрешены. Как бы вы это истолковали?

101V=100

так как

10 1V = 100

или как

101 V = 100

или как

1 01V = 100

Итак, это было объявлено незаконным.


1
Незначительные числа: номера строк должны быть в столбцах 1-6, а исполняемый код - после столбца 8. С другой стороны, он DO 10 I=1,50может быть неоднозначно проанализирован как DO1 0I=1,50[кстати, если использовать точку вместо запятой, оператор становится присваиванием переменная с плавающей запятой с именем DO10I.
суперкат

Интересное объяснение! Это имеет смысл для старых языков, но все еще заставляет меня задаться вопросом, почему мы все еще продолжаем выбирать дизайн для таких языков, как Python, JavaScript или R.
Чарльз Клейтон,

Я определенно помню это с BASIC и считаю, что это, вероятно, самая веская практическая причина практики. Технически, однако, я смутно помню, что на самом деле он может вернуться к раннему ассемблеру. Я не уверен, что такое ассемблер, и вполне могу ошибаться.
Брайан Чендлер

42

Потому что при лексическом анализе во время компиляции исключается возврат с возвратом. Переменная как:

Apple;

компилятор сразу узнает, что это идентификатор, когда он встретит букву «А».

Однако переменная вроде:

123apple;

компилятор не сможет решить, является ли это числом или идентификатором, пока он не достигнет 'a', и в результате ему потребуется возврат с возвратом.


2
Чтобы ответить, вспомнив мой класс проектирования компилятора, этот ответ идет прямо! Kudos
nehem

15

Компиляторы / парсеры / лексические анализаторы были для меня давным-давно, но я думаю, что помню, как было трудно однозначно определить, представляет ли числовой символ в модуле компиляции литерал или идентификатор.

Языки, где пробел незначителен (например, ALGOL и оригинальный FORTRAN, если я правильно помню), не могут принимать числа для начала идентификаторов по этой причине.

Это восходит к прошлому - до специальных обозначений для обозначения памяти или числовой базы.


9

Я согласен, что было бы удобно разрешить идентификаторам начинаться с цифры. Один или два человека упомянули, что вы можете обойти это ограничение, добавив знак подчеркивания к своему идентификатору, но это действительно некрасиво.

Я думаю, что отчасти проблема связана с числовыми литералами, такими как 0xdeadbeef, которые затрудняют создание легко запоминающихся правил для идентификаторов, которые могут начинаться с цифры. Один из способов сделать это - разрешить все, что соответствует [A-Za-z _] +, но НЕ является ключевым словом или числовым литералом. Проблема в том, что это приведет к тому, что будут разрешены такие странные вещи, как 0xdeadpork, но не 0xdeadbeef. В конечном счете, я считаю, что мы должны быть справедливыми по отношению ко всему мясу: P.

Помню, когда я впервые изучал C, я чувствовал, что правила для имен переменных были произвольными и ограничительными. Хуже всего то, что их было трудно запомнить, поэтому я отказался от попыток их выучить. Я просто делал то, что считал правильным, и это сработало очень хорошо. Теперь, когда я узнал намного больше, это не кажется таким уж плохим, и я наконец нашел время, чтобы выучить это правильно.


8
LOL - «Проблема в том, что это может привести к странным вещам, таким как 0xdeadpork, но не 0xdeadbeef. В конечном счете, я думаю, что мы должны быть справедливы ко всем видам мяса: P».
mr-euro

6

Вероятно, это решение было принято по нескольким причинам: когда вы анализируете токен, вам нужно только взглянуть на первый символ, чтобы определить, является ли он идентификатором или литералом, а затем отправить его правильной функции для обработки. Так что это оптимизация производительности.

Другой вариант - проверить, не является ли это литералом, и оставить доменом идентификаторов вселенную без литералов. Но чтобы сделать это, вам нужно изучить каждый символ каждого токена, чтобы узнать, как его классифицировать.

Существует также стилистическое значение, идентификаторы которого должны быть мнемоническими, поэтому слова гораздо легче запомнить, чем числа. Когда писалось множество оригинальных языков, задающих стили на следующие несколько десятилетий, они не думали о замене «2» на «to».


6

Имена переменных не могут начинаться с цифры, потому что это может вызвать некоторые проблемы, как показано ниже:

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

каково значение c? равно 4 или 10!

другой пример:

float 5 = 25;
float b = 5.5;

- это первая цифра 5 или объект (оператор.) Аналогичная проблема возникает и со вторым числом 5.

Может быть, есть другие причины. Итак, мы не должны использовать какие-либо цифры в начале имени переменной.


Даже если требуется, чтобы идентификаторы содержали хотя бы один нецифровой символ, нужно было бы также потребовать, чтобы числовые форматы, содержащие буквы, также содержали не буквенно-цифровой символ [например, требовалось, чтобы 0x1234 записывалось как $ 1234 и 1E6 должно было быть записано как 1.E6 или 1.0E6] или имеют странное сочетание допустимых и недопустимых имен идентификаторов.
supercat

4

Использование цифры в начале имени переменной значительно усложняет проверку ошибок во время компиляции или интерпретации.

Разрешение использования имен переменных, начинающихся с числа, вероятно, вызовет огромные проблемы для разработчиков языка. Во время синтаксического анализа исходного кода, всякий раз, когда компилятор / интерпретатор обнаруживал токен, начинающийся с цифры, где ожидалось имя переменной, ему приходилось искать по огромному, сложному набору правил, чтобы определить, действительно ли токен является переменной или ошибкой. , Дополнительная сложность, добавленная к синтаксическому анализатору языка, может не оправдать эту функцию.

Насколько я себя помню (около 40 лет), я не думаю, что когда-либо использовал язык, который позволял бы использовать цифру в начале имен переменных. Я уверен, что это было сделано хоть раз. Может, кто-то здесь действительно где-то видел это.


1
Это не так уж и сложно. Это усложняет лексическую фазу, вот и все. Конечно, когда я брал компиляторы, мне говорили, что лексическое сканирование может занимать более четверти общего времени компиляции.
Дэвид Торнли,

4

Как заметили несколько человек, существует много исторического багажа относительно допустимых форматов для имен переменных. А языковые дизайнеры всегда зависят от того, что они знают, когда создают новые языки.

Тем не менее, почти всегда язык не позволяет именам переменных начинаться с цифр, потому что это правила дизайна языка. Часто это потому, что такое простое правило значительно упрощает синтаксический анализ и лексирование языка. Однако не все разработчики языков знают, что это настоящая причина. Современные лексические инструменты помогают, потому что, если вы попытаетесь определить его как допустимый, они вызовут конфликты при разборе.

OTOH, если в вашем языке есть однозначно идентифицируемый символ для обозначения имен переменных, можно настроить их так, чтобы они начинались с числа. Подобные варианты правил также могут использоваться для разрешения пробелов в именах переменных. Но полученный язык, скорее всего, не будет сильно напоминать какой-либо популярный традиционный язык, если вообще будет.

В качестве примера довольно простого языка шаблонов HTML, который позволяет переменным начинаться с чисел и иметь встроенные пробелы, посмотрите Qompose .


1
На самом деле существует несколько языков, которые позволяют использовать символы для обозначения идентификаторов. Их называют «сигилами», и они есть в Perl и PHP.
Джейсон Бейкер,

За исключением того, что вам по-прежнему не разрешается начинать имя переменной в PHP с числа - это запрещено правилами языка. :-) Но в Qompose можно по той же причине.
staticsan

4

Потому что, если вы разрешили ключевому слову и идентификатору начинаться с числовых символов, лексер (часть компилятора) не мог легко отличить начало числового литерала от ключевого слова, не становясь намного сложнее (и медленнее).


2
Процесс lexing редко является узким местом. Конечно, это усложняет регулярное выражение для токенов идентификаторов, но они все равно могут быть сверхбыстрыми DFA. По сравнению с большинством других задач, которые приходится выполнять компиляторам, время их выполнения - мелочь.

4

Ограничение произвольное. Различные Лиспы позволяют именам символов начинаться с цифр.



2

C ++ не может иметь этого, потому что разработчики языка сделали это правилом. Если бы вы создали свой собственный язык, вы, конечно, могли бы разрешить это, но вы, вероятно, столкнетесь с теми же проблемами, что и они, и решите не позволять этого. Примеры имен переменных, которые могут вызвать проблемы:

0x, 2д, 5555


Это ограничение действует в языках, где такой синтаксис не разрешен.
Джейсон Бейкер,

2

Одна из ключевых проблем ослабления синтаксических соглашений заключается в том, что это вносит когнитивный диссонанс в процесс кодирования. На то, как вы думаете о своем коде, может сильно повлиять отсутствие ясности, которое он привнесет.

Разве не Дайкстра сказал, что «самый важный аспект любого инструмента - это его влияние на пользователя»?


1

Вероятно, потому, что так человеку легче определить, число это или идентификатор, и в силу традиции. Наличие идентификаторов, которые могут начинаться с цифры, не сильно усложнит лексическое сканирование.

Не во всех языках есть запрещенные идентификаторы, начинающиеся с цифры. В Forth они могли быть числами, а маленькие целые числа обычно определялись как слова Forth (по сути, идентификаторы), поскольку было быстрее читать «2» как процедуру для помещения 2 в стек, чем распознавать «2» как число. значение которого равнялось 2. (При обработке ввода от программатора или блока диска система Forth разделяла ввод по пробелам. Она пыталась найти токен в словаре, чтобы узнать, было ли это определенным словом, и в противном случае попытался бы преобразовать его в число, а в противном случае - пометил бы ошибку.)


Дело в том, что у Форта на самом деле нет очень сложного парсера. На самом деле все, о чем он заботится, - это если идентификатор находится между двумя наборами пробелов.
Джейсон Бейкер

1

Предположим, вы разрешили имена символов начинаться с цифр. Теперь предположим, что вы хотите назвать переменную 12345foobar. Как бы вы отличили это от 12345? На самом деле это не так уж сложно сделать с регулярным выражением. Проблема на самом деле заключается в производительности. Я не могу объяснить, почему это так подробно, но, по сути, все сводится к тому факту, что для отличия 12345foobar от 12345 требуется возврат. Это делает регулярное выражение недетерминированным.

Есть гораздо лучшее объяснение этому здесь .


1
Как можно создать регулярное выражение, чтобы разрешить переменную с именем ifqили, doublezно не ifили double? Основная проблема с разрешением идентификаторам начинаться с цифр заключается в том, что существуют существующие формы шестнадцатеричных литералов и чисел с плавающей запятой, которые полностью состоят из буквенно-цифровых символов (языки будут использовать что-то вроде $ 1234 или h'1234 вместо 0x1234 и требовать такие числа, как 1E23, чтобы включить точку, можно избежать этой проблемы). Обратите внимание, что попытки синтаксического разбора C уже могут быть сбиты такими вещами, как 0x12E+5.
суперкат

1

компилятору легко идентифицировать переменную, используя ASCII в ячейке памяти, а не по номеру.


1

Компилятор имеет следующие 7 этапов:

  1. Лексический анализ
  2. Синтаксический анализ
  3. Семантический анализ
  4. Генерация промежуточного кода
  5. Оптимизация кода
  6. Генерация кода
  7. Таблица символов

На этапе лексического анализа во время компиляции фрагмента кода исключается возврат с возвратом. Переменная, такая как Apple, компилятор узнает ее идентификатор сразу, когда он встретит букву «A» на этапе лексического анализа. Однако для такой переменной, как 123apple, компилятор не сможет решить, является ли это числом или идентификатором, пока он не достигнет «a», и ему потребуется возврат с возвратом, чтобы перейти на фазу лексического анализа, чтобы определить, что это переменная. Но компилятором это не поддерживается.

Когда вы разбираете токен, вам нужно только посмотреть на первый символ, чтобы определить, является ли он идентификатором или литералом, а затем отправить его в нужную функцию для обработки. Так что это оптимизация производительности.


0

Я думаю, простой ответ - может, ограничение основано на языке. В C ++ и многих других это невозможно, потому что язык не поддерживает это. Это не разрешено правилами.

Этот вопрос похож на вопрос, почему король не может перемещать четыре клетки за раз в шахматах? Это потому, что в шахматах это недопустимый ход. Может это в другой игре точно. Это просто зависит от правил игры.


За исключением того, что C ++ был изобретен недавно людьми, которые еще живы. Мы можем спросить их, почему они выбрали то, что сделали, и отвергли альтернативы. То же самое не относится к шахматам.
Стив Джессоп

Но я не об этом говорю. Это аналогия того, почему не может быть числа в начале имен переменных, и самый простой ответ - потому что правила языка не позволяют этого.
kemiller2002

Конечно, но я не думаю, что спрашивающий - идиот. Он, наверное, так далеко уже разобрался сам. Вопрос IMO: «Почему правила языка не позволяют этого?». Он хочет преодолеть разрыв между знанием правил и их пониманием.
Стив Джессоп,

Да, поразмыслив над этим, я понял, куда ты идешь. У вас есть пункт. Я предполагаю, что я применял бритву Оккама немного вольно и предполагал, что нет реального ответа на вопрос, почему, кроме того, что переменные не начинаются с чисел, потому что нет чисел.
kemiller2002 05

Я не говорю, что вы ошибаетесь, заметьте, иногда решения органов по стандартизации C ++ действительно превосходят понимание смертных, и вы в конечном итоге получаете «потому что они должны были что-то решить, и они решили это». Но есть, по крайней мере, вопрос :-)
Стив Джессоп

0

Первоначально это было просто потому, что легче запомнить (можно придать ему больше смысла) имена переменных в виде строк, а не чисел, хотя числа могут быть включены в строку, чтобы улучшить смысл строки или разрешить использование того же имени переменной, но обозначить его как имеющий отдельное, но близкое значение или контекст. Например, loop1, loop2 и т. Д. Всегда будут сообщать вам, что вы находитесь в цикле и / или цикл 2 был циклом внутри цикла loop1. Что бы вы предпочли (имеет большее значение) в качестве переменной: адрес или 1121298? Что легче запомнить? Однако, если в языке используется что-то для обозначения того, что это не просто текст или числа (например, $ в адресе $), это действительно не должно иметь значения, поскольку это сообщит компилятору, что то, что следует ниже, следует рассматривать как переменную ( в таком случае).


0

Переменная может рассматриваться как значение также во время компиляции компилятором, поэтому значение может вызывать значение снова и снова рекурсивно.


0

На этапе лексического анализа при компиляции фрагмента кода исключается обратный поиск . Переменная типа Apple; , компилятор узнает свой идентификатор сразу же, когда он встретит букву «A» на этапе лексического анализа. Однако такая переменная, как 123apple; , компилятор не сможет решить, является ли это числом или идентификатором, пока он не достигнет 'a' и ему не потребуется обратный путь, чтобы перейти на фазу лексического анализа, чтобы определить, что это переменная. Но в компиляторе это не поддерживается.

Ссылка


0

Когда дело доходит до объявления переменной, в этом нет ничего плохого, но есть некоторая двусмысленность, когда он пытается использовать эту переменную где-то еще, например:

let 1 = "Привет, мир!" печать (1) печать (1)

print - это общий метод, который принимает все типы переменных. поэтому в этой ситуации компилятор не знает, к какому (1) программисту относится: к 1 целочисленного значения или 1, хранящему строковое значение. может быть, лучше для компилятора в этой ситуации позволить определить что-то подобное, но при попытке использовать этот неоднозначный материал выведите ошибку с возможностью исправления, чтобы исправить эту ошибку и устранить эту неоднозначность.

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.