Pracowałem z nowym programistą C ++ jakiś czas temu, kiedy zadał pytanie: „Dlaczego nazwy zmiennych nie mogą zaczynać się od cyfr?”
Nie mogłem wymyślić odpowiedzi, poza tym, że niektóre liczby mogą zawierać tekst (123456L, 123456U) i nie byłoby to możliwe, gdyby kompilatorzy myśleli, że wszystko z pewną ilością znaków alfa jest nazwą zmiennej.
Czy to była właściwa odpowiedź? Czy jest więcej powodów?
string 2BeOrNot2Be = "that is the question"; // Why won't this compile?
0
które odkłada 0 na stos. inny to0=
sprawdzanie, czy na stosie jest 0.Odpowiedzi:
Ponieważ wtedy ciąg cyfr byłby zarówno prawidłowym identyfikatorem, jak i prawidłową liczbą.
źródło
A
-F
i kończących sięh
. Zaskoczyło mnie, gdy po raz pierwszy próbowałem zdefiniować wytwórnię, która wskazywałaby na dane muzyczne dla Two Part Invention # 13 Bacha (nazwa logiczna?Bach
).Dobrze pomyśl o tym:
Co to jest? 2.0? czy 42?
Podpowiedź, jeśli tego nie rozumiesz, d po liczbie oznacza liczbę poprzedzającą podwójny literał
źródło
d
nie jest poprawnym zmiennym sufiksem literału w C ++. Pływające literały są domyślnie dublowane, możesz użyćf
lub,l
jeśli potrzebujesz liczby zmiennoprzecinkowej lub długiego podwójnego literału.Teraz jest to konwencja, ale zaczęła się jako wymóg techniczny.
W dawnych czasach parsery języków takich jak FORTRAN czy BASIC nie wymagały użycia spacji. Zasadniczo następujące są identyczne:
i
Załóżmy teraz, że przedrostki liczbowe są dozwolone. Jak byś to zinterpretował?
tak jak
lub jako
lub jako
Więc to zostało uznane za nielegalne.
źródło
DO 10 I=1,50
można by je analizować niejednoznacznie jakoDO1 0I=1,50
[nawiasem mówiąc, jeśli użyje się kropki zamiast przecinka, instrukcja staje się przypisaniem do zmienna zmiennoprzecinkowa o nazwieDO10I
.Ponieważ w analizie leksykalnej podczas kompilacji unika się cofania. Zmienna taka jak:
kompilator będzie wiedział, że jest to identyfikator od razu, gdy spotka się z literą „A”.
Jednak zmienna taka jak:
Kompilator nie będzie w stanie zdecydować, czy jest to liczba czy identyfikator, dopóki nie trafi w „a”, w związku z czym wymaga cofnięcia.
źródło
Kompilatory / parsery / analizatory leksykalne były dla mnie dawno, dawno temu, ale wydaje mi się, że pamiętam trudności w jednoznacznym ustaleniu, czy znak numeryczny w jednostce kompilacji reprezentuje literał, czy identyfikator.
Języki, w których przestrzeń jest niewielka (jak ALGOL i oryginalny FORTRAN, jeśli dobrze pamiętam) nie mogły z tego powodu akceptować liczb rozpoczynających identyfikatory.
To sięga daleko wstecz - przed specjalnymi zapisami oznaczającymi pamięć lub bazę numeryczną.
źródło
Zgadzam się, że byłoby przydatne, gdyby identyfikatory zaczynały się od cyfry. Jedna lub dwie osoby wspomniały, że możesz obejść to ograniczenie, dodając podkreślenie do swojego identyfikatora, ale to naprawdę brzydkie.
Myślę, że część problemu wynika z literałów liczbowych, takich jak 0xdeadbeef, które utrudniają wymyślenie łatwych do zapamiętania reguł dla identyfikatorów, które mogą zaczynać się od cyfry. Jednym ze sposobów może być zezwolenie na wszystko pasujące do [A-Za-z _] +, co NIE jest słowem kluczowym ani literałem liczbowym. Problem polega na tym, że doprowadziłoby to do dopuszczenia dziwnych rzeczy, takich jak 0xdeadpork, ale nie 0xdeadbeef. Ostatecznie uważam, że powinniśmy być fair w stosunku do wszystkich mięs: P.
Pamiętam, że kiedy po raz pierwszy uczyłem się C, czułem, że reguły nazw zmiennych są arbitralne i restrykcyjne. Co najgorsze, były trudne do zapamiętania, więc zrezygnowałem z ich uczenia się. Po prostu zrobiłem to, co uważałem za właściwe i zadziałało całkiem nieźle. Teraz, kiedy nauczyłem się dużo więcej, nie wydaje się to takie złe i w końcu udało mi się nauczyć tego dobrze.
źródło
Prawdopodobnie jest to decyzja podjęta z kilku powodów, kiedy analizujesz token, wystarczy spojrzeć na pierwszy znak, aby ustalić, czy jest to identyfikator, czy literał, a następnie wysłać go do odpowiedniej funkcji w celu przetworzenia. Więc to jest optymalizacja wydajności.
Inną opcją byłoby sprawdzenie, czy nie jest to literał, i pozostawienie domeny identyfikatorów jako wszechświat minus literały. Ale aby to zrobić, musiałbyś zbadać każdy znak każdego tokena, aby wiedzieć, jak go sklasyfikować.
Istnieją również implikacje stylistyczne, które mają być mnemonikami, więc słowa są znacznie łatwiejsze do zapamiętania niż liczby. Kiedy pisano wiele oryginalnych języków, ustawiając style na kilka następnych dziesięcioleci, nie myśleli o zastąpieniu „2” przez „do”.
źródło
Nazwy zmiennych nie mogą zaczynać się od cyfry, ponieważ może to powodować pewne problemy, jak poniżej:
jaka jest wartość c? to 4 lub 10!
inny przykład:
czy pierwsza 5 jest liczbą lub jest obiektem (. operatorem). Podobny problem występuje z drugą 5.
Może są inne powody. Dlatego nie powinniśmy używać żadnej cyfry na początku nazwy zmiennej.
źródło
Użycie cyfry na początku nazwy zmiennej znacznie komplikuje sprawdzanie błędów podczas kompilacji lub interpertacji.
Zezwolenie na używanie nazw zmiennych, które zaczynały się jak liczba, prawdopodobnie spowodowałoby ogromne problemy dla projektantów języków. Podczas analizowania kodu źródłowego, za każdym razem, gdy kompilator / interpreter napotkał token zaczynający się od cyfry, na której oczekiwano nazwy zmiennej, musiałby przeszukać ogromny, skomplikowany zestaw reguł, aby określić, czy token jest naprawdę zmienną, czy też błędem . Dodatkowa złożoność dodana do parsera języka może nie uzasadniać tej funkcji.
Odkąd pamiętam (około 40 lat), nie sądzę, żebym kiedykolwiek używał języka, który pozwalałby na użycie cyfry jako początku nazw zmiennych. Jestem pewien, że zostało to zrobione przynajmniej raz. Może ktoś tutaj rzeczywiście gdzieś to widział.
źródło
Jak zauważyło kilka osób, istnieje wiele historycznego bagażu dotyczącego prawidłowych formatów nazw zmiennych. A projektanci języków zawsze są pod wpływem tego, co wiedzą, kiedy tworzą nowe języki.
To powiedziawszy, prawie cały czas język nie pozwala na rozpoczynanie nazw zmiennych liczbami, ponieważ takie są zasady projektowania języka. Często dzieje się tak, ponieważ taka prosta reguła znacznie ułatwia analizowanie i leksowanie języka. Jednak nie wszyscy projektanci języków wiedzą, że to jest prawdziwy powód. Pomagają w tym nowoczesne narzędzia leksykalne, ponieważ jeśli spróbujesz zdefiniować je jako dopuszczalne, dadzą ci konflikty analizy.
OTOH, jeśli twój język ma unikalny, rozpoznawalny znak, który zapowiada nazwy zmiennych, można ustawić je tak, aby zaczynały się liczbą. Podobne odmiany reguł mogą być również używane, aby zezwolić na spacje w nazwach zmiennych. Ale wynikowy język prawdopodobnie nie będzie bardzo przypominał żadnego popularnego języka konwencjonalnego, jeśli w ogóle.
Aby zapoznać się z przykładem dość prostego języka tworzenia szablonów HTML, który zezwala na rozpoczynanie zmiennych od liczb i ma osadzone spacje, spójrz na Qompose .
źródło
Ponieważ jeśli pozwolisz, aby słowo kluczowe i identyfikator zaczynały się od znaków numerycznych, lekser (część kompilatora) nie byłby w stanie łatwo odróżnić początku literału numerycznego od słowa kluczowego bez znacznie bardziej skomplikowanego (i wolniejszego).
źródło
Ograniczenie jest arbitralne. Różne Lispy pozwalają, aby nazwy symboli zaczynały się od cyfr.
źródło
W języku COBOL zmienne mogą zaczynać się od cyfry.
źródło
C ++ nie może tego mieć, ponieważ projektanci języka uczynili z tego regułę. Gdybyś miał stworzyć swój własny język, z pewnością mógłbyś na to pozwolić, ale prawdopodobnie napotkałbyś te same problemy, co oni i zdecydowałby się na to nie zezwalać. Przykłady nazw zmiennych, które mogą powodować problemy:
0x, 2d, 5555
źródło
Jednym z kluczowych problemów związanych z rozluźnieniem konwencji składniowych jest wprowadzenie dysonansu poznawczego do procesu kodowania. Na sposób, w jaki myślisz o swoim kodzie, może mieć duży wpływ brak jasności, który to wprowadził.
Czy to nie Dykstra powiedział, że „najważniejszym aspektem każdego narzędzia jest jego wpływ na użytkownika”?
źródło
Prawdopodobnie dlatego, że człowiekowi łatwiej jest stwierdzić, czy jest to liczba, czy identyfikator, a także tradycja. Posiadanie identyfikatorów, które mogłyby zaczynać się od cyfry, nie skomplikowałoby tak bardzo skanowania leksykalnego.
Nie wszystkie języki mają zabronione identyfikatory zaczynające się od cyfry. We Forth mogą to być liczby, a małe liczby całkowite były zwykle definiowane jako słowa Forth (zasadniczo identyfikatory), ponieważ szybsze było odczytanie „2” jako procedury umieszczania 2 na stosie niż rozpoznawania „2” jako liczby którego wartość wynosiła 2. (Podczas przetwarzania danych wejściowych z programatora lub bloku dyskowego, system Forth podzieliłby dane wejściowe według spacji. Próbowałby przeszukać token w słowniku, aby sprawdzić, czy jest to zdefiniowane słowo, i jeśli nie, spróbowałby przetłumaczyć to na liczbę, a jeśli nie, oznaczałoby błąd.)
źródło
Załóżmy, że pozwoliłeś, aby nazwy symboli zaczynały się od cyfr. Teraz przypuśćmy, że chcesz nazwać zmienną 12345foobar. Jak odróżniłbyś to od 12345? W rzeczywistości nie jest to strasznie trudne do zrobienia z wyrażeniem regularnym. W rzeczywistości problemem jest wydajność. Naprawdę nie potrafię wyjaśnić, dlaczego jest to tak szczegółowe, ale zasadniczo sprowadza się to do faktu, że odróżnienie 12345foobar od 12345 wymaga wycofania. To sprawia, że wyrażenie regularne jest niedeterministyczne.
Jest to znacznie lepsze wyjaśnienie tego tutaj .
źródło
ifq
lub,doublez
ale nieif
lubdouble
? Podstawowym problemem związanym z zezwalaniem na rozpoczynanie identyfikatorów od cyfr byłoby to, że istnieją formy literałów szesnastkowych i liczb zmiennoprzecinkowych, które składają się wyłącznie ze znaków alfanumerycznych (języki używałyby czegoś takiego jak 1234 $ lub h'1234 zamiast 0x1234 i wymagałyby liczb takich jak 1E23, aby uwzględnić kropkę, można uniknąć tego problemu). Zauważ, że próby analizy regex-parsingu C mogą już zostać przerwane przez takie rzeczy jak0x12E+5
.kompilatorowi łatwo jest zidentyfikować zmienną za pomocą ASCII zamiast numeru.
źródło
Kompilator ma 7 faz w następujący sposób:
W fazie analizy leksykalnej podczas kompilowania fragmentu kodu unika się cofania. W przypadku zmiennej, takiej jak Apple, kompilator od razu pozna swój identyfikator, gdy napotka literę „A” w fazie analizy leksykalnej. Jednak w przypadku zmiennej, takiej jak 123apple, kompilator nie będzie w stanie zdecydować, czy jest to liczba, czy identyfikator, dopóki nie trafi w „a” i musi przejść wstecz, aby przejść do fazy analizy leksykalnej w celu zidentyfikowania, że jest to zmienna. Ale nie jest obsługiwany w kompilatorze.
Podczas analizowania tokenu wystarczy spojrzeć na pierwszy znak, aby określić, czy jest to identyfikator, czy literał, a następnie wysłać go do odpowiedniej funkcji w celu przetworzenia. Więc to jest optymalizacja wydajności.
źródło
Myślę, że prosta odpowiedź jest taka, że tak, ograniczenie jest oparte na języku. W C ++ i wielu innych nie może, ponieważ język tego nie obsługuje. Nie jest to wbudowane w zasady, aby to umożliwić.
Pytanie to jest podobne do pytania, dlaczego król nie może poruszać się o cztery pola naraz w szachach? To dlatego, że w szachach jest to nielegalne posunięcie. Czy to na pewno w innej grze. Zależy to tylko od reguł, którymi się kierują.
źródło
Pierwotnie było to po prostu dlatego, że łatwiej było zapamiętać (możesz nadać mu więcej znaczenia) nazwy zmiennych jako łańcuchy zamiast liczb, chociaż liczby mogą być zawarte w ciągu, aby zwiększyć znaczenie ciągu lub pozwolić na użycie tej samej nazwy zmiennej, ale wyznaczyć jako posiadające odrębne, ale bliskie znaczenie lub kontekst. Na przykład pętla 1, pętla 2 itd. Zawsze informowałyby cię, że jesteś w pętli i / lub pętla 2 była pętlą w pętli1. Którą wolisz (ma większe znaczenie) jako zmienną: adres czy 1121298? Który jest łatwiejszy do zapamiętania? Jeśli jednak język używa czegoś do oznaczenia, że nie jest to tylko tekst lub liczby (takie jak $ w adresie $), to naprawdę nie powinno to robić różnicy, ponieważ powiedziałoby to kompilatorowi, że to, co następuje, ma być traktowane jako zmienna ( w tym przypadku).
źródło
Zmienna może być traktowana jako wartość również w czasie kompilacji przez kompilator, więc wartość może wywoływać wartość ponownie i ponownie rekurencyjnie
źródło
W fazie analizy leksykalnej podczas kompilowania fragmentu kodu unika się cofania . Zmienna taka jak Apple; , kompilator będzie znać swój identyfikator od razu, gdy napotka literę „A” w fazie analizy leksykalnej. Jednak zmienna taka jak 123apple; , kompilator nie będzie w stanie zdecydować, czy jest to liczba, czy identyfikator, dopóki nie trafi w „a” i musi przejść wstecz, aby przejść do fazy analizy leksykalnej w celu zidentyfikowania, że jest to zmienna. Ale nie jest obsługiwany w kompilatorze.
Odniesienie
źródło
Nie może być w tym nic złego, jeśli chodzi o deklarowanie zmiennej, ale jest pewna niejednoznaczność, gdy próbuje użyć tej zmiennej w innym miejscu, jak to:
let 1 = "Witaj świecie!" drukuj (1) drukuj (1)
print to ogólna metoda, która akceptuje wszystkie typy zmiennych. więc w tej sytuacji kompilator nie wie, do której (1) odnosi się programista: 1 z wartości całkowitej, czy 1, która przechowuje wartość ciągu. może lepiej dla kompilatora w tej sytuacji jest pozwolić na zdefiniowanie czegoś takiego, ale próbując użyć tej niejednoznacznej rzeczy, przynieś błąd z możliwością korekty, jak naprawić ten błąd i wyczyść tę niejednoznaczność.
źródło