Dlaczego nazwy funkcji numerycznych są niedozwolone?

10

Rozważ następujące:

$ ksh -c '1(){ echo hi;};1'
ksh: 1: invalid function name
$ dash -c '1(){ echo hi;};1'
dash: 1: Syntax error: Bad function name
$ bash -c '1(){ echo hi;};1'
bash: `1': not a valid identifier
bash: 1: command not found
$ mksh -c '1(){ echo hi;};1'
hi

Zasadniczo, starałem się deklarować funkcje 1i 0co byłoby dla shorthands truea false, ale jak widać wpadłem na problem z użyciem nazwy numeryczne funkcje. To samo zachowanie występuje w przypadku aliasów i dwucyfrowych nazw.

Pytanie brzmi „dlaczego”? Czy jest to wymagane przez POSIX? czy po prostu dziwactwo muszli przypominających bourne?

Zobacz także powiązane pytanie z tym.

Sergiy Kolodyazhnyy
źródło
1
Rzeczy, które są wymagane przez posix, to w większości dziwactwa pocisków podobnych do Bourne'a. : P
mur
Widzę, co tu zrobiłeś . . . > :) lol
Sergiy Kolodyazhnyy
4
@fkraiem Proszę odnieść się do meta.askubuntu.com/q/13807/295286 Powłoki / skrypty powłoki są i zawsze były na temat na Ask Ubuntu :) Jest to niezbędny temat do prawidłowego administrowania systemem każdego systemu Ubuntu
Sergiy Kolodyazhnyy
4
Warto zauważyć, że 0jest truew skryptach powłoki i 1jest false(tak naprawdę każdy niezerowy traktowany jest jako fałsz), na wypadek, gdyby ktoś czytający to nie był świadomy. Jest to odwrotnie niż w przypadku większości innych języków programowania.
Ethan Kamiński
2
@EthanKamiński tak, jeśli chodzi o statusy wyjścia poleceń , to absolutnie prawda. Zwracana wartość 0 jest truew powłoce. Jednak w interpretacji arytmetycznej $((...))odwracane są statusy powrotu - 1 oznacza, truea 0 oznacza falsespójność ze składnią języka C. Spróbuj na przykład bash -c 'echo $((1==1));echo $((1==2))' To, co próbowałem zrobić poza tym pytaniem, było w rzeczywistości „odwróceniem” zachowania. Zobacz ostatni przykład mojej odpowiedzi tutaj, aby zobaczyć, co dokładnie próbowałem zrobić. Głupi pomysł, ale mimo to działa
Sergiy Kolodyazhnyy

Odpowiedzi:

14

POSIX mówi:

2.9.5 Polecenie definicji funkcji

Funkcja jest nazwą zdefiniowaną przez użytkownika, która jest używana jako proste polecenie do wywołania polecenia złożonego z nowymi parametrami pozycyjnymi. Funkcja jest definiowana za pomocą „polecenia definicji funkcji”.

Format polecenia definicji funkcji jest następujący:

 fname ( ) compound-command [io-redirect ...]

Funkcja nazywa się fname ; aplikacja powinna upewnić się, że jest to nazwa (patrz Nazwa XBD ) i że nie jest to nazwa specjalnego wbudowanego narzędzia. Implementacja może dopuszczać inne znaki w nazwie funkcji jako rozszerzenie. Implementacja powinna utrzymywać osobne przestrzenie nazw dla funkcji i zmiennych.

I:

3.235 Nazwa

W języku poleceń powłoki słowo składające się wyłącznie z podkreślników, cyfr i alfabetu z przenośnego zestawu znaków. Pierwszy znak imienia nie jest cyfrą.

Uwaga: Przenośny zestaw znaków jest szczegółowo zdefiniowany w Przenośnym zestawie znaków.

Zatem słowo zaczynające się od cyfry nie może być nazwą funkcji.

muru
źródło
Nadal POSIX nie mówi dokładnie dlaczego, ale przyjmuję to jako odpowiedź „Ponieważ standardy”. Dzięki
Sergiy Kolodyazhnyy,
4
@SergiyKolodyazhnyy Powiedziałbym, że jest to dziedziczna rzecz. Ten standard nazw jest dość powszechny również w innych rzeczach (nazwy IIRC C również są zgodne z tym samym standardem), więc prawdopodobnie jest to kwestia uniksowa. Również w C ułatwia to parsowanie
mur
3
@muru w C przyniosłoby niejasności, gdyby było to dozwolone. Np. Co by to 1Lznaczyło? Nazwa funkcji? Czy long intdosłownie?
Ruslan
2
Dodając do powyższego, warto zauważyć, że w C nagie nazwy funkcji mogą działać jako wskaźnik do tej funkcji. Umożliwia to przekazywanie funkcji jako parametrów do funkcji, przechowywanie odwołań do nich w zmiennych itp. Często używane do wywołań zwrotnych. Jest to przeciwieństwo nazwy funkcji, po której następuje (), być może wraz z argumentami w środku, co oznacza wywołanie danej funkcji (i przyjmuje wartość zwracaną przez wywoływaną funkcję). Więc jeśli masz funkcję int f() { return 42; }w C, fjest poprawna w kontekście wskaźnika i f()jest poprawna w kontekście innym niż wskaźnik, liczba całkowita.
CVn
13

Jest to standard w wielu językach, aby zapobiec pomyłkom między operacjami matematycznymi a zmiennymi, funkcjami lub metodami.

Rozważać:

var 1 = 100

print 1*10 //should return 10 but would instead return 1000

var x = 5
x += 1
print x //returns 105, not 6    

def 100(num)
  return num * 1000
end

var y = 10 + 100(10)
print y // returns 100010 instead of 1010

Jak widać, jeśli liczby byłyby dozwolone jako nazwy zmiennych lub funkcji, późniejsze wykonywanie matematyki w programie mogłoby stać się bardzo mylące i musiałbyś wymyślić twórcze obejścia, gdybyś musiał później zrobić matematykę z tymi liczbami. Może również powodować nieoczekiwane wyniki w niektórych językach. Wyobraź sobie, że zwiększasz liczbę dla pętli, ale jedna z cyfr jest już zmienną równą łańcuchowi. Natychmiast rzuciłby błąd. Jeśli nie jesteś oryginalnym autorem kodu, znalezienie błędu może zająć sporo czasu.

W skrócie, dlatego większość języków nie pozwala na użycie liczby jako nazwy zmiennej, funkcji, metody itp.

Josh
źródło
Zamierzałem skomentować: „ale zmienne w powłoce muszą zostać uzupełnione o $rozszerzenie”, ale z drugiej strony, jeśli powłoka jest inspirowana innymi językami, to chyba tak, a poza tym arytmetyczne ((zmienne rozszerzenia nie muszą mieć wiodącej pozycji $. OK, rozumiem to
Sergiy Kolodyazhnyy,
3
Tak, jest to konwencja, ponieważ przyniesie nieoczekiwane wyniki w prawie każdym języku, ale nawet w sytuacji, w której zadziała, może być bardzo trudny do zrozumienia dla każdego, kto będzie musiał pracować nad twoim kodem po tobie.
Josh
2
Rozbudowa arytmetyczna @SergiyKolodyazhnyy pozwala na odwoływanie się do nazw zmiennych bez $, więc jest to. Ale to prawdopodobnie drugorzędne w stosunku do innego powodu „po prostu przestrzegania wspólnej konwencji”
Hobbs
@obbs tak, absolutnie się z tym zgadzam
Sergiy Kolodyazhnyy
1
To wyjaśnienie „większości języków” nie ma sensu dla powłok. Wszystkie pociski w stylu Bourne'a mają parametry, których nazwy wyglądać literałów liczbowych lub operatorów: 0nazwy powłoki lub skryptu 1, 2, ..., dla parametrów pozycyjnych, *dla nich dołączył, -do włączonych opcji, ?za ostatni stan wyjścia, a !dla najnowszy PID zadania asynchronicznego. (Tak więc, nawet w $(( ))The $często jest potrzebne.) Kod pokazany tutaj wykazać sugerowanego uzasadnienie nie jest skryptem powłoki Bourne'a dla każdego stylu, ponieważ nie ma sposobu, aby wykazać to w ten sposób, jak to nie ma zastosowania do im.
Eliah Kagan,
10

W C rozważmy wyrażenie takie jak:

1000l + 2.0f;

Czy 1000lzmienna czy stała? Ponieważ nazwy zmiennych nie mogą zaczynać się cyfrą, musi być stała. To sprawia, że ​​parsowanie jest łatwiejsze i bardziej rygorystyczne (literówki 1000kmożna łatwo złapać). Łatwiej jest też mieć jedną regułę dla zmiennych i nazw funkcji, ponieważ funkcje można również traktować jak zmienne. Teraz, oczywiście, parsery są znacznie bardziej złożone i wydajne, a my mamy takie rzeczy jak niestandardowe literały w C ++. Ale w dawnych czasach prehistorii poświęcenie odrobiny niepotrzebnej elastyczności może znacznie skrócić czas kompilacji (lub interpretacji) (a ludzie nadal narzekają na czasy kompilacji w C ++).

I możesz zobaczyć efekty wpływu C w całym języku powłoki, więc nie jest zaskakujące, że powłoka Bourne'a (lub powłoka C), a zatem POSIX, ograniczyła klasę dozwolonych nazw do tego samego co klasa C.

Olorin
źródło
2
Jak wyjaśniają , jest to poprawne. Nie chodzi o to, że te same rozważania dotyczą wszystkich języków ani o to, że powłoki w stylu Bourne'a mają składnię podobną do C, ale że kultura związana z C była silna i projektanci powłok musieli wymyślić pewne gwarancje co do identyfikatorów dozwolony. Myślę, że można by użyć przykładów „można zobaczyć efekty wpływu C w całym języku powłoki”, ponieważ podobieństwa między nimi naprawdę nie przeważają nad różnicami (na przykład, jakie liczby są uważane za prawdziwe ). Niemniej jednak ta odpowiedź jest poprawna.
Eliah Kagan,
@Eliah prawdopodobnie liczby są również bezpośrednią konsekwencją statusu wyjścia dla sukcesu i porażki w C, więc mam tendencję do myślenia w kategoriach sukcesu i porażki zamiast prawdy i fałszu podczas pisania testów powłoki. Masz rację, że mnóstwo składni powłoki nie przypomina C, ale przykłady obejmują nawiasy klamrowe, średniki, zwarcie &&i ||brak wsparcia dla ASCII nul w ciągach,
Olorin