Witam,
Post by babla[...] chyba musi coś wiedzieć, a nie pierdolić od rzeczy.
Miałeś pecha w swoim życiu, że jakiś psor który nigdy nie wyprodukował
aplikacji, nie serwisował i nie rozwijał jej, który trenował się na
Odrze (nazwa komputera) chrzani trzy po trzy robiąc przy tym mądre miny.
Mnie się też zdarzyło, że uwierzyłem w mądrość swoich nauczycieli ale
życie zweryfikowało moje po(d)glądy.
Jeśli ktoś nie umie poprawnie logicznie uzasadnić dlacego TAK, a
dlaczego NIE, to oznacza to ni mniej ni więcej, że się nie zna i nie
należy tracić czasu na dalsze z nim konwersacje.
1. break i continue są jak najbardziej słuszne i użycie ich w wielu
algorytmach jest jedynym rozsądnym wyjściem
2. czytelność kodu niejednokrotnie jest ważniejsza niż jego wydajność
3. ciekawi mnie jaki masz sposób (inny niż break) na przerwanie pętli
for/do?
Nie bardzo wiem, czemu tak naskoczyliście na Michała - że słucha autorytetów?
Myślę, że to dobrze. W dzisiejszych czasach trudno takowych znaleźć, a to,
że Michał dopiero się uczy i nie zawsze potrafi uzasadnić pewne reguły
i dobrze wykorzystać je w praktyce, to chyba można mu na razie wybaczyć.
A teraz odnośnie poglądów profesora i czytelności kodu z mojego punktu
widzenia - praktyka, który sprzedaje również kody źródłowe komponentów.
Zasada jednego wyjścia z pętli jest stara jak Pascal i programowanie
strukturalne. Gdy te zasady były formułowane nie było w Pascalu instrukcji
break, exit i continue, które zrywają strukturalność programu. Na podstawie
tych zasad próbowano kiedyś dowodzić matematycznie poprawność
działania programów. Ta dziedzina dziś chyba już się nie rozwija, a do
Pascala wprowadzono kilka odstępstw od tych zasad, bo programista
jest z natury leniwy ;-)
Instrukcje break, exit i continue są czytelne i sam je czasem stosuję w
prostych procedurach, ale gdy algorytm jest bardziej skompikowany, to
tylko przeszkadzają. Często wracając do kodu po dłuższej przerwie
zapomina się o "tylnym" wyjściu z pętli lub procedury i potem traci
masę czasu na szukanie "głupich" błędów.
Jeśli chodzi o implementację break, exit i continue, to niczym się ona
nie różni od użycia "goto" poza tym, że nie trzeba deklarować etykiety,
bo miejsce skoku wynika z nazwy instrukcji. Co do używania goto, to
chyba nie muszę tu nic więcej pisać.
Ad. 1.
Break i continue są dzisiaj "legalnymi" instrukcjami w Pascalu, ale
to nie jest powód do potępiania kogoś, za to, że ich nie używa.
BTW. Goto i etykiety też nadal są w definicji języka :-)
Ad. 2.
Dla mnie czytelnośc kodu zawszy była i jest ważna, ale nigdy nie stała
w sprzeczności z wydajnością kodu. Jeśli już czasem trzeba wybierać,
to między wydajnością kodu, a jego rozmiarem, ale nigdy czytelnością.
Ad. 3.
Jeżeli pętla "for to do" wykonywana od First do Last może zakończyć się
na innym elemencie niż Last, to należy użyć innej pętli (while, repeat until).
Tyle mówią zasady. W klasycznym Pascalu (i przy dowodzeniu poprawności
algorytmów) wyjście z pętli "for to do" zawsze nastąpi po osiągnieciu
przez zmienną sterującą wartości Last, a wartość zmiennej sterującej po
wyjściu z takiej pętli jest nieokreślona i zmienna powinna być ponownie
zainicjowana przed jej kolejnym użyciem. Takimi zasadami nadal kieruje
się optymalizator, a użycie w pętli instrukcji Break powoduje pogorszenie
tej optymalizacji.
Przykład podany przez Michała nie był zbyt dobrze zapisany:
Wersja Michała:
while (i<255) do
begin
instr1;
instr2;
Application.procesmessage;
if flaga then
i := 255; // <- i w nastepnym przebiegu sam skończy pętle, bo warunek będzie false
end;
Dla poprawienia czytelności kodu należałoby to zapisać tak:
Wersja A:
Terminated := False;
I := 0;
while not Terminated and (I < 255) do
begin
Inc(I);
Instr1;
Instr2;
Application.ProcessMessages; // jakieś zdarzenie ustawia Terminated na True
end;
Prosto, czytelnie, w pełni strukturalnie i ... rozwojowo !!!
Wyjście z takiej pętli następuje przy Terminated = True lub I = 255
i w dalszej części kodu można te warunki również czytelnie testować,
a przy rozwijaniu programu można dodawać kolejne warunki wyjścia
z pętli i wszystkie można zobaczyć w jednym miejscu (w instrukcji while)
bez przegladania całej zawartości pętli !!!
Kod z użyciem instrukcji Break wyglądałby następująco
Wersja B:
Terminated := False;
I := 0;
while (I < 255) do
begin
Inc(I);
Instr1;
Instr2;
Application.ProcessMessages; // jakieś zdarzenie ustawia Terminated na True
if Terminated then Break;
end;
Na tym kodzie właściwie nie ma żadnego zysku, ani wydajnościowego,
ani pamięciowego, bo jedynie testowanie jednego z warunków zostało
przeniesione na koniec pętli. Za to trzeba przeczytać całą pętlę, żeby
zobaczyć drugi warunek wyjścia.
A przy użyciu pętli "for to do" wyglądałoby to tak:
Wersja C:
Terminated := False;
for I := 1 to 255 do
begin
Instr1;
Instr2;
Application.ProcessMessages; // jakieś zdarzenie ustawia Terminated na True
if Terminated then Break;
end;
Tu kod jest bardziej zwarty i użycie Break wydaje się być uzasadnionym,
bo procedura jest krótka, prosta i czytelna, ale przy bardziej rozbudowanej
używałbym wersji A. Wydajność obliczeniowa i pamięciowa wszystkich trzech
wersji jest właściwie taka sama.
--
pozdrowienia
Krzysztof Szyszka, X-Files Software
Developer of X-Files Components
Borland Technology Partner
_________________________________________
Website: http://www.x-files.pl/ E-mail: ***@x-files.pl