Opcjonalne średniki

10

Najczęściej w imperatywnym języku ogólnego przeznaczenia - średniki jako separatory instrukcji są albo wymagane, albo całkowicie niedozwolone (np. C i Python).

Jednak niektóre języki, na przykład JavaScript, pozwalają zrezygnować z ograniczania instrukcji średnikami na rzecz innych separatorów (takich jak nowa linia).

Jakie są za tym decyzje projektowe? Rozumiem, że średniki są niezbędne przy pisaniu wielu instrukcji w tym samym wierszu, ale czy istnieje jeszcze jeden powód, aby uczynić je obowiązkowymi (oprócz następujących po C)?

Aber Kled
źródło
1
Musisz pomyśleć o terminatorach instrukcji (perl, c) i ogranicznikach instrukcji (javascript, pascal).
5
W Pythonie średników można używać do oddzielania wielu instrukcji w tym samym wierszu. A ponieważ dozwolona jest „pusta” instrukcja, średników można używać na końcu większości instrukcji.
Greg Hewgill
1
I understand that semicolons are essential when writing multiple statements on the same line- Zależy od języka. Mój ulubiony nie ma takich ograniczników, następna instrukcja zaczyna się, gdy wszystkie argumenty funkcji zostaną wyczerpane.
Izkata
1
@MichaelT: Nie sądzę, aby twoje klasyfikacje były poprawne: Perl prawdopodobnie należy do obu grup, a JavaScript faktycznie znajduje się w obozie „zakończeń instrukcji” (ponieważ implementacje są wymagane do wnioskowania średnika przed }lub na końcu pliku).
ruakh
Tak, absolutnie zależy od języka. Domyślam się, że średniki są tylko rodzajem powszechnie uzgodnionej konwencji, którą przestrzega większość projektantów języków. Przynajmniej ma to jakiś sens z bardziej naturalnego punktu widzenia języka. Nawiasem mówiąc, to samo z {i} dla bloków: są one używane przez wiele języków, jednak nie wszystkie i tak naprawdę nie musisz tego robić. Nie ma za tym uniwersalnego powodu.
JensG

Odpowiedzi:

24

Ustanowienie ich jako obowiązkowych (lub całkowite ich niedopuszczenie) zmniejsza liczbę przypadków narożnych, eliminuje potencjalne źródło niejasnych błędów i upraszcza projektowanie kompilatora / interpretera.

Projektanci języków, którzy zdecydowali się na ich opcjonalność, wybrali dwuznaczność w zamian za większą elastyczność syntaktyczną.

Robert Harvey
źródło
7
@RobertHarvey Heretic! Powinien być jeden, oczywisty sposób na zrobienie tego i tylko jeden. Nawiasem mówiąc, jest tylko jeden sposób, aby to zrobić w Perlu.
1
BTW - niektóre języki mają ogólnie nadmiarowość w gramatyce, więc włączenie średnika opcjonalnego jest w praktyce niekiedy dwuznaczne. To powiedziawszy, myślę, że średnik to nieodpowiednia odrobina nadmiarowości - bardzo lubię Haskella, w którym zamiast argumentów wstawiasz pareny i przecinki. OK, możesz też wstawić średnik w Haskell, ale tak naprawdę to nie to samo, co Javascript.
Steve314,
2
IIRC problem polega na tym, że nie pasują one do modelu formalnego, ale że generatory parsera nie generują dobrych komunikatów o błędach. Tzn. Mają ograniczoną wiedzę na temat typowych błędów, a ręcznie pisany parser może uzyskać znacznie bardziej użyteczny komunikat o błędzie. Gcc na przykład używał żubra do gramatyki C. Podobnie problem polega na tym, że „przypadki krawędzi” nie są formalnymi przypadkami krawędzi, ale miękkimi - tj. Dla parsera AST jest jasny, a dla człowieka AST „jest jasny”, ale nie zgadzają się, jak AST jest.
Maciej Piechotka,
2
@Maciej Piechotka - Nie chciałem sugerować, że pareny są opcjonalne w Haskell. Mówię o porzuceniu czegoś zbędnego jako decyzji projektowej języka. Chodzi o to, że nie używasz parens ani przecinków do wywołania funkcji w Haskell. Państwo może przekazać krotki jako argument, ale to nadal składnia krotki, nie do przejścia argumenty. Haskell (i ML i inni) „upuścili” pareny i przecinki dla argumentów funkcji w tym sensie, że istnieje wspólna konwencja w innych językach (od Algola?), Ale Haskell tego nie robi.
Steve314,
1
@Maciej Piechotka - Oczywiście i tak nigdy nie była to tak naprawdę konwencja uniwersalna - tylko dlatego, że języki używane przez rodzinę Algol nie oznaczają, że inne języki określają się w stosunku do tego, więc moje „odrzucone” twierdzenie jest błędne w tym sensie - ale ze wszystkimi języki z rodziny C w dzisiejszych czasach są trochę takie.
Steve314,
15

JavaScript pokazał nam, że to bardzo zły pomysł. Na przykład:

return
0;

W C zwraca wartość 0. W JavaScript zwraca to, undefinedponieważ średnik wstawia się po instrukcji return, i nie jest od razu oczywiste, dlaczego kod się psuje, chyba że wiesz o szczegółach automatycznego wstawiania średnika.

Mason Wheeler
źródło
1
@delnan: Python nie jest zaprojektowany tak, aby wyglądał jak C. Jest dobrze znany z opartego na wcięciach, a zatem zorientowanego na linię i nie wymaga średników. JavaScript wymaga tego technicznie ; wstawia jedną, gdy znajdzie brakującą, co przekształca coś, co wygląda jak jedna poprawna składniowo instrukcja w dwie odrębne instrukcje o zupełnie innej semantyce.
Mason Wheeler
7
To nie jest zły pomysł, jest mylący dla osób, które próbują używać JavaScript bez zawracania sobie głowy poznaniem jego automatycznego wstawiania średnika . Być może zamiast powiedzieć „to bardzo zły pomysł”, można by dokładniej powiedzieć „opcjonalne wstawianie średników wprowadza pułapki dla programistów, którzy nie wychodzą i nie poznają wszystkich szczegółów”.
TehShrike
4
@delnan: Zaskakujące jest to, że JavaScript zwykle nie wstawia średnika na końcu wiersza, z wyjątkiem naprawienia nieprawidłowego programu. After returnjest tylko jednym z niewielu przypadków, w których JavaScript wstawi średnik, nawet jeśli program byłby bez niego poprawny. (Ale oczywiście podważa to punkt Masona Wheelera. Problem nie polega na tym, że średniki są opcjonalne, chodzi o to, że reguły są niespójne.)
ruakh
6
@TehShrike: Włączenie średników opcjonalnych wprowadza pułapki dla wszystkich programistów, ponieważ arbitralnie interpretuje literówki zamiast pytać, co masz na myśli. Wszyscy od czasu do czasu robią literówkę.
Jan Hudec
1
javascript wykazał, że jego implementacja opcjonalnych średników jest wadliwa. Nie pokazuje, że opcjonalne średniki są same w sobie złe.
CodesInChaos
4

Upraszcza to nieco gramatykę i analizator składni, dzięki czemu średniki są obowiązkowe. Zasadniczo umożliwia leksykowi zrzucenie wszystkich białych znaków, w tym znaków nowej linii, a analizator składni nie musi się o to martwić.

Z drugiej strony, kiedy i tak zaczniesz chcieć powiedzieć parserowi o białych znakach, nie jest trudno ustawić opcjonalne średniki. Często możesz po prostu połączyć je z whitespacetokenem, a parser poradzi sobie z tym dobrze.

Na przykład spróbuj wstawić średnik do następującej serii instrukcji C.

functionCall(3, 4) 9 + (3 / 8) variable++ while(1) { printf("Hello, world\n") }

Chociaż jest kilka dziwnych rzeczy, których nie można już robić, while(1);w większości przypadków jest to stosunkowo łatwe dzięki nowoczesnym technikom analizowania, aby ustalić, gdzie kończą się instrukcje bez określonego ogranicznika. Nawet jeśli nadal chcesz pozwolić na dziwne rzeczy, nie jest tak trudno stworzyć newline_or_semicolonnieterminalne.

Karl Bielefeldt
źródło
Kiedy C został pierwotnie opracowany na początku lat siedemdziesiątych, terminatory instrukcji były potrzebne, aby uprościć kompilatory. W połowie lat 90., kiedy opracowano Javascript, nie było to już tak dużym problemem.
Sean McSomething,
3

Średniki są przydatne w gramatyce z 2 powodów. Po pierwsze, pozwala na dzielenie długich instrukcji na wiele wierszy bez pochlebnych znaków kontynuacyjnych (mówię o tobie, Fortran i Basic). Po drugie, parser ma sposób na „zrezygnowanie” z parsowania, gdy składnia jest naprawdę skomplikowana z powodu literówki. Kradnąc z przykładu Karla Bielefeldta,

functionCall(3, 4) 9 + (3 / 8) variable++ while(1) { printf("Hello, world\n") }

wyobraź sobie, że wpisałeś jeden dodatkowy otwarty paren:

functionCall((3, 4) 9 + (3 / 8) variable++ while(1) { printf("Hello, world\n") }

gdzie jest teraz błąd? Jeśli masz średnik, parserowi łatwiej jest zrezygnować z pierwszego średnika. Może nawet kontynuować parsowanie po średniku, jeśli chce.

functionCall((3, 4);  <- something is wrong here. emit error and keep going.
                      9 + (3 / 8); variable++; while(1) { printf("Hello, world\n"); }

Teraz parserowi łatwiej jest zgłosić błąd i łatwiej zlokalizować linię / kolumnę, w której wystąpił.

Mark Lakata
źródło
1
Fortran i Basic przynajmniej mają przyzwoicie wybrane znaczniki kontynuacji linii (odpowiednio & i _). Dla zwykłego „OMG, co oni sobie myśleli”, nic nie przebije FoxPro. Aby kontynuować linię, użyłeś średnika.
DougM
2

Średniki nie zawsze są niczym lub niczym, jak wspomniałeś w swoim pytaniu. Na przykład gramatyka Lua jest starannie zaprojektowana, aby była wolna (wszystkie białe znaki, w tym znaki nowej linii, można zignorować), ale także bez konieczności używania żadnych średników. Na przykład następujące programy są równoważne:

--One statement per line
x = 1
y = 2

--Multiple statements per line
x = 1 y = 2

--You can add semicolons if you want but its just for clarity:
x = 1; y = 2
hugomg
źródło
0

Pomijając wszystkie projekty i konstrukcje, uważam, że wielu programistów pochodzi z różnych środowisk, a niektórzy nauczyli się używać średnika, a niektórzy nie. Wiele nowych języków, które się pojawiają, nie wymaga średnika, ale nadal pozwala na jego istnienie. Myślę, że może to być po prostu sposób na zachęcenie większej liczby programistów do nauki pisania kodu w tych nowych językach bez konieczności rezygnacji z nawyków od samego początku.

Słuchawki HaxZ
źródło