W wielu językach (szeroka lista, od C do JavaScript):
- przecinki
,
oddzielne argumenty (np.func(a, b, c)
), natomiast - średniki
;
oddzielne instrukcje sekwencyjne (npinstruction1; instruction2; instruction3
.).
Dlaczego więc odwzorowanie odwrócono w tych samych językach dla pętli :
for ( init1, init2; condition; inc1, inc2 )
{
instruction1;
instruction2;
}
zamiast (co wydaje mi się bardziej naturalne)
for ( init1; init2, condition, inc1; inc2 )
{
instruction1;
instruction2;
}
?
Jasne, for
jest (zazwyczaj) nie jest funkcją, ale argumenty (czyli init
, condition
, increment
) zachowują się bardziej jak argumenty funkcji niż sekwencji instrukcji.
Czy jest to spowodowane względami historycznymi / konwencją, czy też istnieje uzasadnienie dla wymiany ,
i ;
pętli?
programming-languages
syntax
loops
Piotr Migdal
źródło
źródło
;
nie|
?” (lub Dlaczego używamy „inny” nie „inaczej”? )), która nie jest sprawa dla jednego języka, ale duża ich liczba. Odpowiedź, że np. „Został napisany w C jako skrót dla pętli while (i wiele instrukcji dla inc było rozważanych dopiero później), a ludzie nie chcieli jej zmieniać, aby uniknąć irytacji programistów”, byłby w porządku.Odpowiedzi:
Technicznie odwzorowanie nie jest „odwrócone”.
W rzeczywistości mamy tutaj inny kontekst składniowy, w którym te same symbole są używane w różny sposób. Nie porównujemy z podobnymi, więc nie ma mapowania i nie ma mocnego argumentu za spójnym mapowaniem opartym na spójności semantycznej.
Dlaczego więc nie zrobić tego na odwrót?
Myślę, że przyczyny wynikają z „naturalnego” znaczenia
,
i;
. W angielskim języku pisanym średnik to „silniejsza” przerwa niż przecinek, a glif średnika jest bardziej widoczny niż przecinek. Te dwie rzeczy razem sprawiają, że obecny układ wydaje mi się (dla mnie!) Bardziej naturalny.Ale jedynym sposobem, aby wiedzieć na pewno, dlaczego dokonano wyboru składni, byłoby, gdyby projektanci C mogli powiedzieć nam, co myślą w 1970 roku. Wątpię, aby mieli wyraźną pamięć o decyzjach technicznych podjętych w tak odległych czasach.
Nie znam żadnego języka przed C, który używałby składni podobnej do C dla pętli „for”:
Donal Fellows zauważa, że BCPL i B nie miały równoważnej konstrukcji.
Odpowiedniki FORTRAN, COBOL i Algol-60 (i Pascal) były mniej ekspresyjne i miały składnie, które nie przypominały składni „for”.
Ale języki takie jak C, C ++ i Java, które pojawiły się po C, wyraźnie pożyczają swoją składnię „for” od C.
źródło
,
vs;
) to (słabsze vs silniejsze zerwanie), a nie (rozdzielacz krotek vs sekwencja), prawda? Nadal dla mnie nie jest oczywiste, czy argumenty lub instrukcje wymagają silniejszych przerw (jak w wielu przypadkach dla sekwencji instrukcji, przerwy są niejawne (patrz np. JavaScript (np.i++[line break]j++
))), Ale przynajmniej teraz rozumiem, dlaczego obecna konwencja nie jest „oczywiście odwrócony”.FOR i = e1 TO e2 BY e3 DO c
(wyrażenia e1..e3, polecenie c), które bardziej przypominają składnię BASIC. Źródłofor
składni wprowadzono C (nie było B lub BCPL).Piszemy pętle takie jak:
Język mógł zostać zdefiniowany tak, aby pętle wyglądały następująco:
Pomyśl jednak o tej samej pętli zaimplementowanej za pomocą pętli while:
Zauważ, że instrukcje
x=0
ix++
są zakończone średnikami. Nie są to wyrażenia takie jak w wywołaniu funkcji. Średniki służą do oddzielania instrukcji, a ponieważ dwa z trzech elementów w pętli for są instrukcjami, to właśnie tam są używane. Pętla for to tylko skrót do takiej pętli while.Ponadto argumenty tak naprawdę nie działają jak argumenty funkcji. Drugi i trzeci są wielokrotnie oceniane. To prawda, że nie są sekwencją, ale nie są też argumentami funkcyjnymi.
Również fakt, że możesz użyć przecinków, aby mieć wiele instrukcji w pętli for, jest w rzeczywistości czymś, co możesz zrobić poza pętlą for.
jest całkowicie poprawnym stwierdzeniem, nawet poza pętlą for. Nie znam jednak żadnego praktycznego zastosowania poza pętlą for. Chodzi o to, że przecinki zawsze dzielą instrukcje; nie jest to specjalna funkcja pętli for.
źródło
x = 0; y = 0;
i (w nawiasach klamrowych)x++; y++;
...;
naturalna jest sekwencja instrukcji , niekoniecznie oddzielająca dowolne instrukcje (czy to tylko różnice w gustach?). A w obecnej konwencji czasami zdarza się, że i tak oddzielamy sekwencje zdań przecinkami ...(foo)?bar++, qux++:bletch
--- Gdzie chcesz, aby?:
wyrażenie robiło dwie rzeczy zamiast jednej. Wartość zwracana, jeślifoo
jest prawdą toqux
, ale zarównobar
iqux
dostać zwiększany.W C i C ++ jest to przecinek, a nie przecinek.
Gramatyka
for
pętli jest podobnaW przypadku twojego pytania:
Zauważ, że operator przecinka pozwala wykonać wiele akcji w jednej instrukcji (tak jak widzi to kompilator). Gdyby twoja sugestia została zaimplementowana, gramatyka byłaby niejasna co do tego, kiedy programista zamierzał napisać instrukcję operatora przecinek lub separator.
Krótko mówiąc,
;
oznacza koniec instrukcji.for
Pętla jest słowem kluczowym następuje lista opcjonalnych sprawozdania otoczone()
. Instrukcja operator przecinek pozwala na użycie,
w jednej instrukcji.źródło
for
pętli wyraźnie zezwala na instrukcję (deklarację) jako jej pierwszą część. (C ++ dopuszczał deklaracje w połowie funkcji, w przeciwieństwie do swojego poprzednika C89). Nie można generalizować takich instrukcji w różnych językach, nawet dla 2 języków tak bliskich jak C i C ++.for ( {<expression>}? ; {<expression>}? ; {<expression>}? ) <statement>
dla C ifor ( for-init-statement; conditionopt ; expressionopt ) statement
dla C ++ --- The „;” oznacza nie tylko terminator instrukcji. Po pętli for nie następują instrukcje zawarte w ().Nie ma odwrócenia pojęciowego.
Średniki w C reprezentują więcej głównych podziałów niż przecinki. Oddzielają oświadczenia i deklaracje.
Główne podziały w pętli for są takie, że istnieją trzy wyrażenia (lub deklaracja i dwa wyrażenia) oraz ciało.
Przecinki, które widzisz w C dla pętli for, nie są częścią składni pętli for. To tylko przejawy operatora przecinka.
Przecinki są głównymi separatorami między argumentami w wywołaniach funkcji i między parametrami w deklaracjach funkcji, ale średniki nie są używane. Pętla for ma specjalną składnię; nie ma to nic wspólnego z funkcjami ani wywołaniami funkcji.
źródło
Być może jest to coś specyficznego dla C / C ++, ale zamieszczam tę odpowiedź, ponieważ na składnię opisywanych przez ciebie języków zależy głównie od składni C.
Poza tym pytania, na które wcześniej udzielono odpowiedzi, są prawdą, z technicznego punktu widzenia, dzieje się tak również dlatego, że w C (i C ++) przecinek jest tak naprawdę operatorem , który można nawet przeciążać . Użycie operatora średnika (
operator;()
) prawdopodobnie utrudniłoby pisanie kompilatorów, ponieważ średnik jest aksjomatycznym terminatorem wyrażeń.Interesujące jest to, że przecinek jest powszechnie używany jako separator w całym języku. Wygląda na to, że operator przecinka jest wyjątkiem, który jest używany głównie do uzyskiwania
for
pętli z działającymi wieloma warunkami, więc o co chodzi?W rzeczywistości
operator,
jest zbudowany tak, aby robić to samo, co w definicjach, listach argumentów itd.: Został zbudowany w celu oddzielenia wyrażeń - coś, czego,
nie może zrobić konstrukcja składniowa . Może jedynie rozdzielić to, co zostało zdefiniowane w standardzie.Jednak średnik nie rozdziela się - kończy . I to prowadzi nas z powrotem do pierwotnego pytania:
Przecinek rozdziela wyrażenia w trzech częściach pętli, podczas gdy średnik kończy część (inicjalizację, warunek lub refleksję) definicji pętli.
Nowsze języki programowania (jak C #) mogą nie pozwalać na przeciążanie operatora przecinków, ale najprawdopodobniej zachowały składnię, ponieważ zmiana wydaje się w jakiś sposób nienaturalna.
źródło
for
oświadczeniu;
symbol jest po prostu używany jako separator. Oddziela 3 składniowe części instrukcji. Nie ma trzeciego średnika do „zakończenia” listy wyrażeń progresywnych. Jest zakończony innym tokenem -)
.Dla mnie są one używane w mniejszym stopniu niż ich sens językowy. Przecinki są używane z listami i średnikami z bardziej oddzielnymi częściami.
W
func(a, b, c)
mamy listę argumentów.instruction1; instruction2; instruction3
jest może listą, ale listą oddzielnych i niezależnych instrukcji.Podczas gdy
for ( init1, init2; condition; inc1, inc2 )
mamy trzy oddzielne części - listę inicjalizacji, warunek i listę wyrażeń przyrostowych.źródło
Najłatwiej to zobaczyć:
jest:
Innymi słowy, te x = 0 coś jest w rzeczywistości instrukcją / instrukcją, a nie parametrem. Wstawiasz tam oświadczenie. Dlatego są one oddzielone średnikiem.
W rzeczywistości nie ma możliwości oddzielenia ich przecinkami. Kiedy ostatnio wstawiałeś jako parametr x <10? Robisz to, jeśli chcesz raz komputer x <10 i wstawić wynik tej operacji jako parametr. Tak więc w świecie przecinków wstawiłbyś x <10, jeśli chcesz przekazać wartość x <0 do funkcji.
Tutaj określasz, że program powinien sprawdzać x <10 za każdym razem, gdy pętla jest przekazywana. To jest instrukcja.
x ++ jest zdecydowanie kolejną instrukcją.
To są wszystkie instrukcje. Więc są one rozdzielone średnikiem.
źródło
for
switch
lubreturn
wewnątrz definicji pętli for (tj.for(int i = 0; if(i > 1024) { return; } ; switch (i % 3) { case 0; case 1: i++; case 2: i++; } ) { ... }
) --- nie możesz. To nie jest oświadczenie. Zamiast tego jest zdefiniowany jakofor ( {<expression>}? ; {<expression>}? ; {<expression>}? ) <statement>
int i = 0
zdecydowanie NIE jest wyrażeniem. Zestaw reguł opisujących wyrażenie jest dość złożony, biorąc pod uwagę to, co może stanowić wyrażenie, ale konstrukcjaTYPE NAME = EXPRESSION
nie pasuje do żadnej z tych reguł.