Goto - zło wrodzone, czy zło urojone ; )?

0

Goto w programowaniu uznawane jest za zło wrodzone. We wszystkich książkach jakie napotkałem, radzi się go w ogóle nie używać. Tylko dlaczego? Jakoś nie za bardzo przekonywuje mnie do tego fakt, jakoby tworzył on kod nieczytelny. To tak, jakby zabronić używania instrukcji switch, tudzież continue.
Dlaczego więc mam utrudniać sobie pracę i bawić się w całkiem nieczytelne zakresy, zamiast użyć goto. A co do miłośników estetyki, przecież przy goto, zawszę w komentarzu można napisać coś ala:
//Patrz: linia x., co raczej powinno sprawić, że będzie on wystarczająco czytelny, by go używać.
A jakiego wy jesteście zdania? Także jesteście przeciwnikami używanie goto (jeżeli tak, to dlaczego)? Prosiłbym o rozsądne argumenty oraz o niepowielanie bzdur na temat "unmaintable spaghetti code".

0

Z tego co się orientuję, to goto stało się złem po krytycznych artykułach Dijkstry. Problem polegał na tym, że programiści nadużywali tej instrukcji i przez to powstawał spaghetti code. Samo w sobie goto nie jest złe, tylko trzeba umieć właściwie z niego korzystać. Tak zresztą jest ze wszystkim.

0

Samo w sobie goto nie jest złe, tylko trzeba umieć właściwie z niego korzystać.

Na moje to właśnie należy umieć programowac by nie korzystać z goto.

A tak z innej beczki :

jakoby tworzył on kod nieczytelny. To tak, jakby zabronić używania instrukcji switch,

A co jest nieczytelnego w switch ?

0

Wiecie, po to bozia dała nam funkcje żebyśmy nie programowali liniowo (co nie jest do końca prawdą - CPS gdyby się uprzeć można uznać za formę programowania liniowego). Problem w tym, źe tak wtedy jak i teraz wielu ludzi nie potrafiło sensownie kodu zorganizować i łatało niedoróbki stertą etykietek i goto.

0
polaczek17 napisał(a)

jakoby tworzył on kod nieczytelny. To tak, jakby zabronić używania instrukcji switch,

A co jest nieczytelnego w switch ?

W gruncie rzeczy korzysta ona z etykiet, czyli także jest swego rodzaju goto. Udowodnić możesz to sobie, wpisując w zasięgu switch`a, instrukcje, np.: "goto case2".

polaczek17 napisał(a)

Na moje to właśnie należy umieć programowac by nie korzystać z goto.

Co prawda trzeba umieć kombinować, ale po co mam się bawić pętlą i break`iem (który i tak nie jest zawszę skuteczny), skoro mogę coś rozpisać tak:

      Poczatek:
      /*Funkcje menu*/
      if(cin>>Od_nowa == true) goto Poczatek;
0

Co prawda trzeba umieć kombinować, ale po co mam się bawić pętlą i break`iem (który i tak nie jest zawszę skuteczny), skoro mogę coś rozpisać tak:

To mam lepsze pytanie:
"Po co bawić się for-em , breakiem skoro mamy while ?"

goto jest brzydkie. W ogóle nie rozumiem jak można z niego korzystać. To boli w oczy aż na serio.

0
Bobise napisał(a)

W gruncie rzeczy korzysta ona z etykiet, czyli także jest swego rodzaju goto. Udowodnić możesz to sobie, wpisując w zasięgu switch`a, instrukcje, np.: "goto case2".

Ta? I co się stanie?

0

Goto i switch to jednak coś troszkę innego. Goto należy IMO traktować jako zło i sami programiści są temu winni. Jestem zdania, że jeśli jakieś narzędzie jest przez większość czasu używane zdecydowanie źle, to warto "zabronić jego używania". Tj. wbijać ludziom, że samo skorzystanie z niego jest złe, mimo że w rzeczywistości nie musi tak być. Chodzi o to, że większość osób faktycznie korzystałaby z niego źle. Co, Ty byś akurat korzystał dobrze, jeden z drugim? No pewnie! Na bank! Jakoś mnie takie głosy nie dziwią i założę się, że w czasach gdy goto królowało, ludzie też tak myśleli ("może inni stosują to niepoprawnie, ale na pewno ja tego nie robię w moim kodzie!").

Jednocześnie rozpoznaję, że goto jest do kilku rzeczy przydatne. I tutaj nowoczesne języki często zapewniają konstrukcje, które "ukrywają" goto i nadają się tylko do obsługi konkretnego przypadku -- jednego z tych, w których goto jest faktycznie dobre.

Przykładem takich konstrukcji może być switch. Jego struktura jest w gruncie rzeczy jasna, mimo że poniekąd opiera się na goto. Nie jest tak jednak do końca: nie we wszystkich językach można ręcznie skakać po poszczególnych etykietach (w Javie nie ma przecież goto, mimo że jest switch). A to, że switch tak naprawdę polega na skokach... if-else też na tym polega! Chodzi tylko o to, że instrukcje warunkowe, czy instrukcja wyboru są bardziej semantyczne. Lepiej pokazują i opisują intencje programisty. Goto może reprezentować cokolwiek.

A już sztandarowym przykładem na pseudo-goto jest break ze skokiem do etykiety. To IMO przydatna konstrukcja i należy jej używać. Ciężko jej nawet nadużyć: służy do zwykłego wyskakiwania z zagnieżdżonych pętli. Do czego innego się tego zastosować nie da. A wyskoczenie z zagnieżdżonej pętli przy użyciu breaka z etykietą jest wydajniejsze i moim zdaniem czytelniejsze od ustawienia jakichś flag. Sprawiać to może jedynie takie problemy, że jak ktoś ma poczwórnie zagnieżdżoną pętlę, to zamiast np. wydzielić funkcję dla dwóch wewnętrznych, używa właśnie breaka z etykietą. I szkoda następuje w momencie, gdy break pozwala mu wygodnie olać fakt, że ma w jednej funkcji 4 zagnieżdżone pętle.

Niemniej jednak break z etykietą jest IMO przydatny nawet wtedy, gdy mamy przepisową liczbę dwóch-trzech zagnieżdżonych pętli.

A wracając do switcha, to rzeczywiście ta instrukcja sprawia dużo problemów. Właśnie poprzez tę konieczność pisania break. Mi jakoś zdarzają się one stosunkowo rzadko, ale nawet Douglas Crockford opowiada pewną ironicznie-śmieszną anegdotę na ten temat. Ktoś mu zwrócił w mailu uwagę, że JSLint (taki popularny parser sprawdzający jakość kodu napisany przez Crockforda) nie wypisuje ostrzeżenia, jeśli ktoś "zapomni" napisać break po jakimś case w switchu. Crockford mu odpisał, że tego ostrzeżenia nie ma, bo może ktoś rzeczywiście chce przejść z jednego case'a do drugiego i specjalnie pominął breaka. I że doświadczonym programistom to nie sprawia problemów. Na drugi dzień, albo jeszcze tego samego dnia, Crockford dostał maila od tego samego kolesia. W mailu koleś zgłosił buga w samym JSLincie, który był spowodowany... brakującym breakiem w switchu :). Od tego czasu JSLint wymaga, by po każdym case był break :).

0
Bobise napisał(a)
polaczek17 napisał(a)

Na moje to właśnie należy umieć programowac by nie korzystać z goto.

Co prawda trzeba umieć kombinować, ale po co mam się bawić pętlą i break`iem (który i tak nie jest zawszę skuteczny), skoro mogę coś rozpisać tak:

Poczatek:
/Funkcje menu/
if(cin>>Od_nowa == true) goto Poczatek;


Wiesz, tym kodem właśnie pokazałeś jakiś wybitny i 'umiejący kombinować'. Niezależnie co byś zrobił to i tak wyjdzie z tego absurd.
0

Niestety, nie programowałem w czasach, gdy panowało goto (pewnie nawet nie miałem wtedy komputera). Jednak po części potrafię sobie wyobrazić, niektóre kody z jego użyciem. Jednak, nie rozumiem osób, które uważają, że jak ktoś użyję "goto" to jest kolejnym debilem, lub osobą zaczynającą przygodę z programowaniem. Moim zdaniem to nieprawda. Bo gdyby nie "goto" to kod byłby pisany linia pod linią (bowiem, czym jak nie ulepszonym goto są wszelakie instrukcje, jak i funkcje)?
Nie jestem wybitny, a to był pseudo kod.

0
Bobise napisał(a)

Bo gdyby nie "goto" to kod byłby pisany linia pod linią (bowiem, czym jak nie ulepszonym goto są wszelakie instrukcje, jak i funkcje)?

Funkcja to funkcja, skok (warunkowy) to skok. Poza tym linia pod linią? Bozia dała średniki, każdy kod można w jednej linijce upchnąć!

http://en.wikipedia.org/wiki/Continuation-passing_style - goto czy nie goto?

0
Świętowit napisał(a)

Funkcja to funkcja, skok (warunkowy) to skok. Poza tym linia pod linią? Bozia dała średniki, każdy kod można w jednej linijce upchnąć!

W tym celu umieściłem tam cudzysłów (przy goto).
I cóż z tego. Uważasz, że bez funkcji itd. ludzie pisaliby w jednej linijce cały kod ; d?

0

Goto jest złe, bo jest za MAŁO elastyczne.
Co mi po goto, którym nie mogę wskoczyć do środka funkcji... [diabel]

Jest taka nowoczesna odmiana "goto", że można wyskoczyć z kodu w połowie, a później wskoczyć z powrotem i kontynuować obliczenia... Nazywa się "kontynuacja". Jest to w Pythonie i Rubym, a najbardziej zaawansowana postać będzie w Scali 2.8.

http://www.scala-lang.org/node/2096

Swoją drogą, ktoś na tym mechaniźmie zrobił normalne goto (którego standardowo w Scali nie ma):
http://blog.richdougherty.com/2009/03/goto-in-scala.html

;]

0

Byla juz taka dyskusja i mozna bylo jej po prostu poszukac. A goto to zlo, bo cecha dobrego kodu jest dobra organizacja. Goto to latanie dziur powstalych w wyniku braku czasu na myslenie, analiza i zaprojektowanie. Nawet jak zaprojektowanie opiera sie na patrzeniu w sciane przez minute i mazanie po kartce papieru.

0
Bobise napisał(a)

Uważasz, że bez funkcji itd. ludzie pisaliby w jednej linijce cały kod ; d?

Dobra, ale to był przykład, że nie trzeba pisać 'linijka pod linijką'.

To jak z tym:

http://en.wikipedia.org/wiki/Continuation-passing_style - goto czy nie goto?

@Krolik, właśnie pokazałeś, że wśród programistów Scali też ludzi 'zdrowych' psychicznie nie brakuje, tworzyć goto w języku funkcyjnym, poważne jak cholera. Chociaż byli już inny cwaniacy implementujący Haskellową monadę kontynuacji, więc jakoś specjalnie mnie to nie zaskakuje.

0

Zapomniałbym, warto zauważyć, że GOTO jest potrzebne - ostatnio, po kilkunastu latach oczekiwania wprowadzono GOTO do PHP. Developerzy PHP nie mogą się mylić.

0
Świętowit napisał(a)

Zapomniałbym, warto zauważyć, że GOTO jest potrzebne - ostatnio, po kilkunastu latach oczekiwania wprowadzono GOTO do PHP. Developerzy PHP nie mogą się mylić.

Kurde, 5 lat w tym programowalem, przestalem - pewnie podswiadomie wyczuwalem, ze brak mi czegos do szczescia. W innych jezykach sie balem uzywac, ale w PHP to moze byc ten nowy, lepszy swiat! :D

0
Świętowit napisał(a)

Developerzy PHP nie mogą się mylić.

O kurcze! Faktycznie! Społeczność developerów PHP ma tylu dobrych programistów, ich stosunek do ogółu ludzi piszących w tym języku jest tak dobry, a jakość kodu tworzonego w PHP jest tak korzystna w porównaniu do innych języków, że... że... z miejsca mnie tym przekonałeś!

Powyższy akapit jest sponsorowany przez litery: I, R, O, N, I (drugi raz, bo zapłaciła 2x), N (też!) oraz A ;).

0

Mała dygresja ze strony programisty mającego do czynienia z COBOLem. Instrukcja GOTO (względnie CALL) służyła pierwotnie do wywoływania konkretnych bloków kodu. Tworząc program dzielono go na bloki (dziś funkcje/metody, ale nie do końca), które wywoływano za pomocą GOTO, a stan programu był globalny, zatem nie było potrzeby przekazywania parametrów. GOTO zastępuje też bardzo ładnie rekurencyjne wywołania w językach, które nie mają takiej możliwości wprost.
Później wprowadzono bardziej przyjazne funkcje i metody, ale instrukcja GOTO została (nawet w Javie jest, ale nie używane) ponieważ wydawała się być potrzebna. W praktyce programiści nie potrafiąc poradzić sobie z jakimś problemem (zazwyczaj z rekurencją z nietrywialnym punktem stopu) zaczęli nadużywać tej instrukcji. Spowodowało to wspomniane teksty Dijkstry i zapłonęły stosy.

Czy używać? Współczesne języki mają zazwyczaj do dyspozycji taką instrukcję, ale jednocześnie udostępniają znacznie lepsze i wygodniejsze mechanizmy.

na koniec kod javowy z czymś podobnym do GOTO:


LABEL: {

   // tu coś liczymy 
   if( warunek)
     break LABEL;
}

Fajne... i dlatego nie używamy dziś GOTO

0

Spróbujcie obyć się bez goto w "językach", w których nie ma if-else (pliki wsadowe w Windows).

0
bo napisał(a)

Spróbujcie obyć się bez goto w "językach", w których nie ma if-else (pliki wsadowe w Windows).

Jak sie nie ma co sie lubi, to sie lubi co sie ma. Jednak w dzisiejszych jezykach alternatywa jest zwykle lepsza i mniej rozwalajaca kod.

0

Jesli goto jest bardziej czytelnym rozwiazaniem to czemu nie zastosowac ?
Zdarza sie to bardzo rzadko ale wystarczy popatrzyc na chociazby .NET, wewnatrz czasami jest ono stosowane (zlozone przetwarzanie wzorcow znakow).

0

Z tego co wiem w .NET stosowanie Goto jest zalecane (tzn nie jest niezalecane) tylko przy skakaniu do etykiet w switchu.

Powiem tak: jeśli goto sprawia że kod jest czytelniejszy i prostszy do analizy - użyj goto. Tylko pamiętaj że jeśli TOBIE się wydaje czytelniejszy to nie oznacza że będziesz tak uważał jeśli do kodu wrócisz po roku, albo jeśli ktoś inny do niego podejdzie. Amen.

0

Znam 2 przypadki gdzie użycie goto jest uzasadnione:

  • wyskakiwanie z zagnieżdżonych pętli
  • w językach, w których nie można w jakiś sposób zasymulować bloku finally (na przykład w C) do zwalniania lokalnych zasobów,

A wskakiwać w środek funkcji można longjumpem ;)

0

Dotykamy tu powaznego problemu "czytelnosc kodu". To samo mozna powiedziec o zle zaprojektowanych funkcjach/klasach. Niestety te tez czesto sie zdarzaja - szczegolnie, ze zaczyna sie moda na projektowanie i kazdy chce uzyc jakiegos rozwiazania (np. wzorca projektowego) nie do konca zapoznajac sie z problemem ale bardziej z klimatu - bede guru.

Coz pozostaje zdefiniowac na sztywno pojecie "czytelnosc kodu", mi wydaje sie to niemozliwe (swoja droga kod ma byc finalnie czytelny dla procesora a tam mamy ... jmp :> ).

0

@bo:
To oczywiste, że jeśli korzystasz z batchów (czy nawet ASM-a) to używasz instrukcji skoków. Btw., wbrew temu co piszesz, w plikach wsadowych Windows JEST if-else. Jest nawet instrukcja call. Ale doskonale rozumiem, że w języku o tak ubogiej składni trzeba tego GOTO nieraz użyć.

@reichel:
Możesz dać jakiś konkretny przykładzik? Często słyszę, że "ale w niektórych sytuacjach to po prostu nie da się inaczej i trzeba tak". Sam tak nieraz mówię. A zwykle okazuje się, że jak ktoś poda konkretny fragment, to po pewnej analizie okazuje się, że da się to zrobić inaczej i to lepiej. Wtedy ktoś podaje następny przykład, ale znowu okazuje się, że to wcale nie jest dobre zastosowanie danej konstrukcji i że można zastosować coś innego i że wyjdzie lepiej.

Dodam, że nie interesuje mnie w tym momencie wychodzenie z zagnieżdżonych pętli -- ten przypadek rozpoznaję i uważam, że można użyć jakiejś odmiany goto (tj. breaka z etykietą).

0

Właśnie, wzorce projektowe. Ostatnimi czasy stają się coraz bardziej 'trendy i cool', przez co zaczynają być nadużywane - niektórzy programiści(?) zaczynają myśleć jak sprowadzić problem do standardowego wzorca projektowego zamiast zastanowić się nad dobrym, prawidłowym rozwiązaniem. W efekcie otrzymujemy papkę, której nikt ogarnąć nie może, znacznie dłuższą niż sensowne rozwiązanie.

0

@Świętowit:
Ponownie: jakieś przykłady? Przynajmniej jeden, taki praktyczny?

Wzorce projektowe zostały stworzone m.in. właśnie po to, by każdy kto spojrzy na kod, w którym zastosowany wzorzec od razu wiedział o co chodzi.

0

@up: Zastosowanie polimorfizmu, interfejsu i 2 klas dziedziczacych z klasy abstrakcyjnej zamiast zrobic jednego ifa, w ktorym obsluga prawdy i falszu zamyka sie po 10 linijek. Lekki przerost formy nad trescia.

0

Zgoda, wzorce są standardem, problem w tym, że niektórzy wciskają je na siłę w każde 10 linijek kodu, implementując najprostsze algorytmy. Znajdę przykład z życia to wrzucę, gdzieś kod takiego projektu chyba na dysku jeszcze zachowałem.

1 użytkowników online, w tym zalogowanych: 0, gości: 1