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

некоторое время назад я работал с новым разработчиком c++, когда он задал вопрос: "Почему имена переменных не могут начинаться с чисел?"

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

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

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

24 ответов


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

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

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

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

что такое a? 2.0? или 42?

подсказка, если вы ее не получите, d после числа означает число до того, как оно будет двойным литералом


теперь это конвенция, но она началась как техническое требование.

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

10 V1=100
20 PRINT V1

и

10V1=100
20PRINTV1

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

101V=100

as

10 1V = 100

или

101 V = 100

или as

1 01V = 100

Итак, это было незаконно.


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

Apple;

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

однако переменная, как:

123apple;

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


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

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

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


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

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

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


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

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

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


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

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

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


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

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

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

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


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


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


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

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

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

еще пример:

float 5 = 25;
float b = 5.5;

первый 5 ряд, или объект (. оператор) Есть аналогичная проблема со вторым 5.

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


COBOL позволяет переменным начинаться с цифры.


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

0x, 2d, 5555


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

разве не Дикстра сказал ,что"самым важным аспектом любого инструмента является его влияние на пользователя"?


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

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


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

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


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


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

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


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


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


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

ссылка


компилятор имеет 7 фаз следующим образом:

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

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

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


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

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

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