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

Я работал с новым разработчиком 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;

Что это? 2,0? или 42?

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

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

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

10 V1=100
20 PRINT V1

а также

10V1=100
20PRINTV1

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

101V=100

как

10 1V = 100

или как

101 V = 100

или как

1 01V = 100

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

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

Apple;

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

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

123apple;

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

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

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

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

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

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

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

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

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

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

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

float 5 = 25;
float b = 5.5;

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

0x, 2д, 5555

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Ссылка

Другие вопросы по тегам