Чому імена змінних не можуть починатися з цифр?


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 знаходиться в стеці.
Інго

12
Чому це питання настільки популярне, а відповіді так неправильні? Багато мов дозволяють змінним починатися з чисел. C ++ не робить, але це лише зручне обмеження, яке дозволяє уникнути певних неоднозначностей. Іноді ТАК дивує мене всіма неправильними способами.
david.pfx

5
Якщо сьогодні це питання було задано на ПЗ, воно буде називатися на основі думки і закриватиметься. Дякую за запитання.
Бун

Відповіді:


116

Тому що тоді рядок цифр буде дійсним ідентифікатором, а також дійсним числом.

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

37
Що робити, якщо вони сказали, що змінні не можуть бути лише числами. Тоді що?
Піролістичний

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

39
Якщо це повинні бути числа + альфа, то ви все одно можете зробити String 0x123 = "Hello World". Якщо ви не вказали, що назви змінних - це "числа + альфа, які не розбираються з дійсним числовим позначенням", і це просто нерозумно.
eaolson

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

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

116

Ну подумайте про це:

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

Що таке? 2,0? або 42?

Підказка, якщо ви цього не отримаєте, d після числа означає число, перш ніж воно буде подвійним буквальним


11
Це насправді [відносно] пізні позначення ("d" для "подвійний"), стандарт CR II89 C89. Провідні числові показники в ідентифікаторах неможливі, якщо ця конструкція є мовою, але це не причина, що числові дані не можуть запустити ідентифікатор.
Кен Ніж

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

1
Це для Java, і, хоча початкове питання стосувалося C ++, воно також стосується багатьох інших мов, як, наприклад, Java. Але я згоден Це не первісна причина, по якій ідентифікатори не можуть починатися з цифр.
Піролістичний

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.
supercat

Цікаве пояснення! Що має сенс для старих мов, все ще змушує мене замислитися, чому ми все ще продовжували вибір дизайну для таких мов, як Python або JavaScript або R.
Чарльз Клейтон

Я напевно пам’ятаю це з BASIC і вважаю, що це, мабуть, найбільш вагома практична причина цієї практики. У технічному плані я смутно пам'ятаю, що це може бути фактично поверненим до мови ранньої збірки. Я не впевнений, що таке асемблер, і я дуже добре можу помилитися.
Брайан Чендлер

42

Оскільки у лексичному аналізі під час складання уникається зворотного відстеження. Змінна типу:

Apple;

компілятор дізнається, що це ідентифікатор відразу, коли він зустріне букву "A".

Однак змінна типу:

123apple;

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


2
Щоб відповісти, пам’ятаючи мій клас дизайнів-компіляторів, Ця відповідь іде прямо правильно! Kudos
nehem

15

Компілятори / парсери / лексичні аналізатори були для мене дуже давно, але, я думаю, пам’ятаю, що виникли труднощі з однозначним визначенням того, чи числовий символ у блоці компіляції являє собою буквальний чи ідентифікатор.

Мови, де простір незначний (наприклад, ALGOL та оригінальний FORTRAN, якщо я правильно пам’ятаю), не могли прийняти цифри для початку ідентифікаторів з цієї причини.

Це відбувається назад - перед спеціальними позначеннями для позначення бази даних чисел.


9

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

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

Коли я вперше вивчив С, я пам'ятаю, як відчував, що правила змінних імен були довільними та обмежувальними. Найгірше, що їх важко було запам'ятати, тому я відмовився намагатися їх навчитися. Я просто зробив те, що відчував себе правильно, і це спрацювало досить добре. Тепер, коли я навчився багато іншого, це не здається таким поганим, і я нарешті взявся навчитися правильно.


8
LOL - "Проблема полягає в тому, що це призвело б до того, щоб дозволити дивні речі, такі як 0xdeadpork, але не 0xdeadbeef. Зрештою, я думаю, що ми повинні бути справедливими до всіх страв: P".
г-н-євро

6

Ймовірно, рішення, яке було прийняте з кількох причин, під час розбору маркера вам потрібно лише подивитися на перший символ, щоб визначити, чи є він ідентифікатором чи буквальним, а потім відправити його в правильну функцію для обробки. Отже, це оптимізація продуктивності.

Іншим варіантом було б перевірити, чи не є він буквальним, і домен ідентифікаторів залишити всесвітом за мінусом літералів. Але для цього вам доведеться вивчити кожного символу кожного маркера, щоб знати, як його класифікувати.

Існують також стилістичні наслідки, що ідентифікатори повинні бути мнемонічними, тому слова запам'ятовуються набагато простіше, ніж числа. Коли писалося багато оригінальних мов, встановлюючи стилі протягом наступних десятиліть, вони не думали про заміну «2» на «на».


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 точно з тієї ж причини.
статис

4

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


2
Процес лексингу рідко є вузьким місцем. Звичайно, це робить регекс для лексем ідентифікаторів складнішим, але вони все ще можуть бути надшвидкими DFA. Час виконання цих арахісів порівняно з більшістю інших компіляторів завдань, які повинні виконати.

4

Обмеження довільне. Різні Lisps дозволяють назви символів починати з цифр.



2

C ++ не може його мати, оскільки мовні дизайнери зробили це правилом. Якби ви створили свою власну мову, ви, безумовно, могли це дозволити, але ви, мабуть, зіткнетеся з тими ж проблемами, що і вони, і вирішите не допустити. Приклади імен змінних, які можуть викликати проблеми:

0x, 2d, 5555


Це обмеження зберігається в мовах, де такий тип синтаксису заборонений.
Джейсон Бейкер

2

Однією з ключових проблем щодо розслаблення синтаксичних умовностей є те, що воно вводить когнітивний дисонанс у процес кодування. Як ви думаєте про свій код, може бути глибоко впливає відсутність ясності, яку це введе.

Чи не Дикстра сказав, що "найважливішим аспектом будь-якого інструменту є його вплив на його користувача"?


1

Можливо, тому, що людині простіше сказати, чи є це чи ідентифікатором, і через традицію. Наявність ідентифікаторів, які можуть починатися з цифри, не сильно ускладнить лексичне сканування.

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


Річ у тім, що Forth насправді не має дуже складного аналізатора. Дійсно, все це хвилює, якщо ідентифікатор знаходиться між двома наборами пробілів.
Джейсон Бейкер

1

Припустимо, ви дозволили назви символів починати з цифр. Тепер припустимо, ви хочете назвати змінну 12345foobar. Як би ви відрізнили це від 12345? Насправді це не дуже важко зробити з регулярним виразом. Проблема - це насправді одна з ефективності. Я не можу пояснити, чому це дуже докладно, але це, по суті, зводиться до того, що для диференціації 12345foobar від 12345 потрібно зворотний трек. Це робить регулярний вираз недетермінованим.

Там набагато краще пояснити це тут .


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

1

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


1

Компілятор має 7 фаз наступним чином:

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

Уникає зворотного відстеження на етапі лексичного аналізу при складанні фрагмента коду. Змінна, як Apple, компілятор дізнається свій ідентифікатор відразу, коли він зустріне символ "A" у фазі лексичного аналізу. Однак, змінної на зразок 123apple, компілятор не зможе визначити, чи є її номером чи ідентифікатором, поки не потрапить на 'a', і воно потребує зворотного відстеження, щоб перейти на етапі лексичного аналізу, щоб визначити, що це змінна. Але це не підтримується в компіляторі.

Коли ви розбираєте маркер, вам потрібно лише подивитися на перший символ, щоб визначити, чи є це ідентифікатором чи буквалом, а потім надіслати його правильній функції для обробки. Отже, це оптимізація продуктивності.


0

Я думаю, що проста відповідь - це може, обмеження засноване на мові. У C ++ та багатьох інших він не може, оскільки мова не підтримує його. Це не вбудовано в правила, щоб це допустити.

Питання схоже на питання, чому король не може переміщати чотири проміжки одночасно в шахах? Це тому, що в Шахах це незаконний хід. Чи може це в іншій грі точно. Це просто залежить від правил, які виконуються.


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

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

Звичайно, але я не думаю, що запитувач є імбецилом. Він, мабуть, опрацював це далеко вже сам. Питання ІМО полягає в тому, "чому правила мови цього не дозволяють?". Він хоче подолати розрив між знанням правил та їх розумінням.
Стів Джессоп

Так, поміркувавши над цим, я зрозумів, куди ти йдеш. Ти правий. Я здогадуюсь, що я застосував бритву Оккама трохи вільно, і припустив, що немає реальної відповіді на те, чому, крім того, що змінні не починаються з чисел, тому що немає чисел.
kemiller2002

Я не кажу, що ви помиляєтесь, розум, іноді рішення органів стандартизації C ++ перевершують смертне розуміння, і ви закінчуєте це, "бо вони повинні були щось вирішити, і вони вирішили це". Але є, принаймні, питання, яке потрібно йому задати :-)
Стів Джессоп

0

Спочатку це було просто тому, що простіше запам'ятати (ви можете надати йому більше значення) імена змінних як рядки, а не числа, хоча числа можуть бути включені в рядок, щоб поліпшити значення рядка або дозволити використовувати те саме ім'я змінної, але позначають його як окремий, але близький сенс чи контекст. Наприклад, loop1, loop2 і т.д. завжди дасть вам знати, що ви знаходитесь у циклі, та / або цикл 2 був циклом у циклі1. Який би ви хотіли (має більше значення) як змінна: адреса або 1121298? Що легше запам’ятати? Однак, якщо мова використовує щось для позначення того, що це не просто текст чи цифри (наприклад, $ у $ address), це дійсно не повинно змінювати значення, оскільки це скаже компілятору, що те, що випливає далі, слід розглядати як змінну ( в цьому випадку).


0

Змінна може розглядатися як значення також під час часу компіляції компілятором, тому значення може викликати значення знову і знову рекурсивно


0

Під час складання фрагмента коду уникнути зворотного відстеження на етапі лексичного аналізу . Змінна, як Apple; , компілятор дізнається свій ідентифікатор відразу, коли він зустріне символ "A" на етапі лексичного аналізу. Однак змінна типу 123apple; компілятор не зможе визначити, чи є його число чи ідентифікатор, поки він не потрапить на 'a', і йому потрібно зворотний трек для проходження фази лексичного аналізу, щоб визначити, що це змінна. Але це не підтримується в компіляторі.

Довідково


0

З цим не може бути нічого поганого, коли йдеться про декларування змінної. Але є певна неоднозначність, коли вона намагається використовувати цю змінну десь в іншому місці:

нехай 1 = "Привіт, світ!" друк (1) друк (1)

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

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.