Wszyscy zdają sobie sprawę z listów Dijkstry do redaktora: przejdź do oświadczenia uważanego za szkodliwe (także tutaj .html transkryptu i tutaj .pdf), a od tego czasu nastąpił ogromny nacisk, aby unikać oświadczenia goto, gdy tylko jest to możliwe. Chociaż można użyć goto do wytworzenia niemożliwego do utrzymania, rozrastającego się kodu, pozostaje on jednak w nowoczesnych językach programowania . Nawet zaawansowaną strukturę kontroli kontynuacji na schemacie można opisać jako wyrafinowane goto.
Jakie okoliczności uzasadniają użycie goto? Kiedy najlepiej tego uniknąć?
Jako kolejne pytanie: C udostępnia parę funkcji, setjmp i longjmp, które zapewniają możliwość przejścia nie tylko w bieżącą ramkę stosu, ale w dowolną ramkę wywołującą. Czy należy je uważać za tak niebezpieczne, jak goto? Bardziej niebezpieczne?
Sam Dijkstra żałował tego tytułu, za który nie był odpowiedzialny. Pod koniec EWD1308 (także tutaj .pdf) napisał:
Wreszcie krótka historia do nagrania. W 1968 r. W komunikatach ACM opublikowano mój tekst pod tytułem „ Oświadczenie goto uznane za szkodliwe ”, które w późniejszych latach będzie najczęściej przywoływane, niestety, często przez autorów, którzy nie widzieli go więcej niż jego tytuł, który stał się kamieniem węgielnym mojej sławy, stając się szablonem: widzieliśmy różnego rodzaju artykuły pod tytułem „X uważane za szkodliwe” dla prawie każdego X, w tym jeden zatytułowany „Dijkstra uważany za szkodliwy”. Ale co się stało? Złożyłem artykuł pod tytułem „ Sprawa przeciwko oświadczeniu goto”, który, aby przyspieszyć publikację, redaktor zmienił się w„ list do redakcji ”, nadając mu nowy tytuł własnego wynalazku! Redaktorem był Niklaus Wirth.
Dobrze przemyślanym klasycznym tekstem na ten temat, który można dopasować do tego, który napisał Dijkstra, jest Programowanie strukturalne z użyciem go w oświadczeniach Donalda E. Knutha. Czytanie pomaga przywrócić kontekst i nie-dogmatyczne zrozumienie tematu. W tym artykule przedstawiono opinię Dijkstry w tej sprawie, która jest jeszcze mocniejsza:
Donald E. Knuth: Uważam, że przedstawiając taki pogląd, tak naprawdę nie zgadzam się ostro z pomysłami Dijkstry, ponieważ ostatnio napisał on: „Proszę, nie wpadnij w pułapkę, wierząc, że jestem strasznie dogmatyczny wobec [ przejdź do oświadczenia]. Mam niewygodne wrażenie, że inni tworzą z niej religię, tak jakby koncepcyjne problemy programowania można rozwiązać za pomocą jednej sztuczki, prostej formy kodowania! ”
źródło
goto
.goto
: hakowanie ustrukturyzowanych narzędzi programistycznych razem w celu wdrożeniagoto
.Odpowiedzi:
Poniższe stwierdzenia są uogólnieniami; chociaż zawsze można powołać się na wyjątek, zwykle (według mojego doświadczenia i skromnej opinii) nie warto ryzykować.
Przypisy do powyższego:
W odniesieniu do pkt 2 rozważ następujący kod:
W punkcie „zrób coś” w kodzie możemy stwierdzić z dużą pewnością, że
a
jest większa niżb
. (Tak, ignoruję możliwość niezapełnionego przepełnienia liczb całkowitych. Nie bagatelizujmy prostego przykładu.)Z drugiej strony, jeśli kod odczytał w ten sposób:
Wielość sposobów dotarcia do etykiety 10 oznacza, że musimy dużo ciężej pracować, aby mieć pewność co do relacji między tym punktem
a
ab
tym. (W rzeczywistości w ogólnym przypadku jest to niezdecydowane!)Jeśli chodzi o punkt 4, całe pojęcie „pójścia gdzieś” w kodzie jest tylko metaforą. Wewnątrz procesora nic tak naprawdę nie „trafia” poza elektronami i fotonami (ciepło odpadowe). Czasami rezygnujemy z metafory dla innej, bardziej użytecznej. Pamiętam, że spotkałem (kilka dekad temu!) Język, w którym
został zaimplementowany na maszynie wirtualnej przez skompilowanie działania 1 i działania 2 jako pozaparametrowych procedur bez parametrów, a następnie za pomocą pojedynczego dwuargumentowego kodu maszynowego VM, który wykorzystał wartość logiczną warunku do wywołania jednego lub drugiego. Pomysł polegał po prostu na „wybierz, co wywołać teraz”, a nie „idź tu lub idź tam”. Znów tylko zmiana metafory.
źródło
true
ifalse
są różnego rodzaju), a każda gałąź if / else jest w zasadzie lambda.goto
w nowoczesnym języku programowania (Go) stackoverflow.com/a/11065563/3309046 .Mój współpracownik powiedział, że jedynym powodem korzystania z GOTO jest zaprogramowanie się tak daleko w kącie, że jest to jedyne wyjście. Innymi słowy, odpowiednio zaprojektuj z wyprzedzeniem i nie będziesz musiał później używać GOTO.
Pomyślałem, że ten komiks pięknie ilustruje to, że „mógłbym zrestrukturyzować przepływ programu lub użyć jednego małego„ GOTO ”. GOTO jest słabym wyjściem, gdy masz słaby projekt. Welociraptory żerują na słabych .
źródło
Czasami warto używać GOTO jako alternatywy dla obsługi wyjątków w ramach jednej funkcji:
Wygląda na to, że kod COM dość często wpada w ten schemat.
źródło
Mogę sobie przypomnieć tylko raz, używając goto. Miałem serię pięciu zagnieżdżonych zliczonych pętli i musiałem być w stanie wcześnie wyrwać się z całej struktury, zależnie od pewnych warunków:
Mogłem po prostu z łatwością zadeklarować zmienną typu boolean i użyć jej jako części warunku dla każdej pętli, ale w tym przypadku zdecydowałem, że GOTO jest tak samo praktyczne i tak samo czytelne.
Żadne velociraptory mnie nie zaatakowały.
źródło
goto
i dało nam programowanie strukturalne, również z tego samego powodu odrzuciło wczesne powroty. Wszystko sprowadza się do tego, jak czytelny jest kod, jak jasno wyraża intencje programisty. Utworzenie funkcji w innym celu niż uniknięcie użycia źle sformułowanego słowa kluczowego powoduje złą spójność: lekarstwo jest gorsze niż choroba.goto
, można jawnie określić cel. Za pomocąbreak 5;
(1) muszę policzyć zamknięcia pętli, aby znaleźć miejsce docelowe; oraz (2) jeśli struktura pętli kiedykolwiek się zmieni, może wymagać zmiany tej liczby, aby zachować prawidłowe miejsce docelowe. Jeśli mam zamiar tego uniknąćgoto
, zysk powinien polegać na tym, że nie muszę ręcznie śledzić takich rzeczy.Już mieliśmy tę dyskusję i podtrzymuję swój punkt widzenia .
Ponadto, mam dość ludzi opisujących struktury języka na wyższym poziomie jako „
goto
w przebraniu”, ponieważ wyraźnie nie mamy punkt w ogóle . Na przykład:To kompletny nonsens. Każda struktura sterowania może być wdrożona pod względem,
goto
ale ta obserwacja jest całkowicie trywialna i bezużyteczna.goto
nie jest uważany za szkodliwy z powodu jego pozytywnych skutków, ale z powodu jego negatywnych konsekwencji, które zostały wyeliminowane przez programowanie strukturalne.Podobnie powiedzenie „GOTO jest narzędziem i jak wszystkie narzędzia mogą być używane i nadużywane” jest zupełnie nie na miejscu. Żaden współczesny pracownik budowlany nie użyłby skały i twierdziłby, że „jest narzędziem”. Skały zostały zastąpione młotami.
goto
został zastąpiony przez struktury kontrolne. Gdyby robotnik budowlany utknął na wolności bez młota, oczywiście użyłby zamiast tego skały. Jeśli programista musi użyć gorszego języka programowania, który nie ma funkcji X, to oczywiście może ona będzie musiała użyćgoto
zamiast tego. Ale jeśli używa go gdziekolwiek indziej zamiast odpowiedniej funkcji językowej, to wyraźnie nie zrozumiała języka poprawnie i używa go niewłaściwie. To naprawdę tak proste.źródło
goto
. Masz rację, o ile nie proponuję argumentów przeciw samymgoto
w sobie - nie zamierzałem - więc nie ma pytań.Goto jest bardzo nisko na mojej liście rzeczy do włączenia do programu tylko ze względu na to. To nie znaczy, że to niedopuszczalne.
Idź może być miły dla maszyn państwowych. Instrukcja switch w pętli jest (w kolejności typowej ważności): (a) w rzeczywistości nie jest reprezentatywna dla przepływu sterowania, (b) brzydka, (c) potencjalnie nieefektywna w zależności od języka i kompilatora. W rezultacie piszesz jedną funkcję dla każdego stanu i robisz takie rzeczy, jak „return NEXT_STATE;” które nawet wyglądają jak goto.
To prawda, że trudno jest kodować maszyny stanów w sposób, który czyni je łatwymi do zrozumienia. Jednak żadna z tych trudności nie wiąże się z użyciem goto i żadnej z nich nie można zmniejszyć za pomocą alternatywnych struktur kontrolnych. Chyba że twój język ma konstrukcję „maszyny stanów”. Mój nie.
W tych rzadkich przypadkach, gdy twój algorytm jest naprawdę najbardziej zrozumiały, jeśli chodzi o ścieżkę przez sekwencję węzłów (stanów) połączoną ograniczonym zestawem dopuszczalnych przejść (gotos), a nie bardziej szczegółowym przepływem sterowania (pętle, warunki warunkowe itp. ), powinno to być wyraźnie określone w kodzie. I powinieneś narysować ładny schemat.
setjmp / longjmp może być przydatne do implementacji wyjątków lub zachowania podobnego do wyjątku. Choć nie są powszechnie chwalone, wyjątki są ogólnie uważane za „prawidłową” strukturę kontroli.
setjmp / longjmp są „bardziej niebezpieczne” niż goto w tym sensie, że trudniej je używać poprawnie, nie wspominając o zrozumieniu.
Usunięcie goto z C nie ułatwiłoby pisania dobrego kodu w C. W rzeczywistości wolałby raczej nie rozumieć, że C powinien działać jako chwalebny język asemblera.
Następnie będą to „wskaźniki uważane za szkodliwe”, a następnie „pisanie kaczek uznane za szkodliwe”. Kto zatem będzie cię bronił, gdy przyjdą zabrać twój niebezpieczny program? Co?
źródło
W Linuksie: Korzystanie z goto W Kernel Code on Kernel Trap toczy się dyskusja z Linusem Torvaldsem i „nowym facetem” na temat wykorzystania GOTO w kodzie Linux. Jest tam kilka bardzo dobrych punktów i Linus ubrany w zwykłą arogancję :)
Niektóre fragmenty:
-
-
źródło
goto cleanup_and_exit
jest jednym z nielicznych „dobrych” zastosowań goto lewo teraz, że mamyfor
,while
iif
zarządzać naszą przepływ sterowania. Zobacz także: programmers.stackexchange.com/a/154980W C
goto
działa tylko w zakresie bieżącej funkcji, która ma tendencję do lokalizowania wszelkich potencjalnych błędów.setjmp
ilongjmp
są znacznie bardziej niebezpieczne, ponieważ są nielokalne, skomplikowane i zależne od wdrożenia. W praktyce są jednak zbyt niejasne i rzadkie, aby powodować wiele problemów.Uważam, że niebezpieczeństwo
goto
w C jest znacznie przesadzone. Pamiętaj, że oryginalnegoto
argumenty miały miejsce w czasach języków takich jak staromodny BASIC, gdzie początkujący pisali kod spaghetti w ten sposób:Tutaj Linus opisuje odpowiednie zastosowanie
goto
: http://www.kernel.org/doc/Documentation/CodingStyle (rozdział 7).źródło
setjmp
/longjmp
zostało określone tylko wtedy, gdy były używane jako sposób przeskakiwania do miejsca w zasięgu z innych miejsc w tym samym zakresie. Gdy kontrola opuści zakres, w którymsetjmp
jest wykonywana, każda próba użycialongjmp
na stworzonej przez nią strukturzesetjmp
spowoduje niezdefiniowane zachowanie.GOTO A * 40 + B * 200 + 30
. Nietrudno dostrzec, jak to było bardzo przydatne i bardzo niebezpieczne.Dzisiaj trudno jest dostrzec wielką wagę tego
GOTO
stwierdzenia, ponieważ ludzie „programowania strukturalnego” przeważnie wygrywają debatę, a dzisiejsze języki mają wystarczającą strukturę kontroli, której można uniknąćGOTO
.Policz liczbę
goto
s we współczesnym programie C. Teraz dodać liczbębreak
,continue
orazreturn
sprawozdania. Ponadto, należy dodać kilka razy użyćif
,else
,while
,switch
lubcase
. To tyle, ileGOTO
miałby Twój program, gdybyś pisał w FORTRAN lub BASIC w 1968 roku, kiedy Dijkstra napisał swój list.W tamtym czasie brakowało języków programowania. Na przykład w oryginalnym BASIC Dartmouth:
IF
oświadczenia nie miałyELSE
. Jeśli chcesz, musisz napisać:Nawet jeśli twoje
IF
oświadczenie nie potrzebowałoELSE
, nadal było ograniczone do jednej linii, która zwykle składała się zGOTO
.Nie było
DO...LOOP
oświadczenia. W przypadku nie-FOR
pętli trzeba było zakończyć pętlę jawnieGOTO
lubIF...GOTO
wrócić do początku.Tam nie było
SELECT CASE
. Musiałeś użyćON...GOTO
.Tak więc skończyłeś z dużą ilością
GOTO
sw swoim programie. I nie mogłeś polegać na ograniczeniuGOTO
s do jednego podprogramu (ponieważGOSUB...RETURN
była to tak słaba koncepcja podprogramów), więcGOTO
mogły one iść gdziekolwiek . Oczywiście utrudniało to kontrolę przepływu.Stąd pochodzi anty-
GOTO
ruch.źródło
420 if (rare_condition) then 3000
//430 and onward: rest of loop and other main-line code
//3000 [code for rare condition]
//3230 goto 430
. Pisanie kodu w ten sposób pozwala uniknąć wszelkich odgałęzień lub skoków w typowym przypadku linii głównej, ale utrudnia śledzenie. Unikanie rozgałęzień w kodzie asemblera może być gorsze, jeśli niektóre rozgałęzienia są ograniczone do np. +/- 128 bajtów i czasami nie mają par komplementarnych (np. Istnieje „cjne”, ale nie „cje”).cjne r0,expected_value,first_comp_springboard
/.../cjne r1,unexpected_value,second_comp_fallthrough
// `ajmp second_comp_target` //first_comp_springboard: ajmp first_comp_target
//second_comp_fallthrough: ...
. Niezbyt fajny wzór kodowania, ale kiedy liczą się poszczególne cykle, robi się takie rzeczy. Oczywiście w latach 60. takie poziomy optymalizacji były ważniejsze niż obecnie, zwłaszcza że współczesne procesory często wymagają dziwnych optymalizacji, a systemy kompilacji just-in-time mogą być w stanie zastosować kod optymalizacji dla procesorów, które nie istniały, gdy kod został napisany.Idź do może zapewnić rodzaj „stand-in” do obsługi „prawdziwych” wyjątków w niektórych przypadkach. Rozważać:
Oczywiście ten kod został uproszczony, aby zajmował mniej miejsca, więc nie odkładaj się zbytnio na szczegółach. Ale rozważ alternatywę, którą widziałem zbyt wiele razy w kodzie produkcyjnym przez programistów dążących do absurdalnych długości, aby uniknąć użycia goto:
Teraz funkcjonalnie ten kod robi dokładnie to samo. W rzeczywistości kod wygenerowany przez kompilator jest prawie identyczny. Jednak w zapał programisty, by uspokoić Nogoto ( budzącego grozę boga upomnień akademickich), ten programista całkowicie złamał podstawowy idiom, który
while
reprezentuje pętla, i zrobił prawdziwą liczbę na temat czytelności kodu. To nie jest lepsze.Morał tej historii jest taki, że jeśli uciekasz się do czegoś naprawdę głupiego, aby uniknąć używania goto, nie rób tego.
źródło
break
instrukcje znajdują się w strukturze kontroli, wyjaśnia dokładnie, co robią. W tymgoto
przykładzie osoba czytająca kod musi przejrzeć kod, aby znaleźć etykietę, która teoretycznie mogłaby faktycznie znajdować się przed strukturą kontroli. Nie mam wystarczającego doświadczenia z C w starym stylu, aby sądzić, że jedno jest zdecydowanie lepsze od drugiego, ale i tak istnieją kompromisy.break
s są wewnątrz pętli, wyraźnie pokazuje, że wychodzą z pętli . To nie jest „dokładnie to, co robią”, ponieważ w rzeczywistości nie ma w ogóle pętli! Nic w tym nigdy nie ma szansy na powtórzenie, ale do końca nie jest to jasne. Fakt, że masz „pętlę”, która nigdy nie działa więcej niż jeden raz, oznacza, że struktury kontrolne są nadużywane. Nagoto
przykład programista może powiedziećgoto error_handler;
. Jest to bardziej jednoznaczne i jeszcze trudniejsze do naśladowania. (Ctrl + F, „moduł obsługi błędów:”, aby znaleźć cel. Spróbuj to zrobić za pomocą „}”.)Donald E. Knuth odpowiedział na to pytanie w książce „Literate Programming”, 1992 CSLI. Na str. 17 znajduje się esej „ Programowanie strukturalne za pomocą instrukcji goto ” (PDF). Myślę, że artykuł mógł zostać opublikowany również w innych książkach.
Artykuł opisuje sugestię Dijkstry i opisuje okoliczności, w których jest to ważne. Podaje także wiele przykładów liczników (problemów i algorytmów), których nie można łatwo odtworzyć przy użyciu tylko pętli strukturalnych.
Artykuł zawiera pełny opis problemu, historię, przykłady i przykłady przeciwne.
źródło
Goto uważany za pomocny.
Zacząłem programować w 1975 roku. Dla programistów z lat 70. słowa „goto uważane za szkodliwe” mówiły mniej więcej, że nowe języki programowania z nowoczesnymi strukturami sterowania są warte wypróbowania. Próbowaliśmy nowych języków. Szybko się przekonaliśmy. Nigdy nie wróciliśmy.
Nigdy nie wróciliśmy, ale jeśli jesteś młodszy, to nigdy tam nie byłeś.
Teraz tło w starożytnych językach programowania może nie być bardzo przydatne, z wyjątkiem wskaźnika wieku programisty. Niezależnie od tego młodsi programiści nie znają tego tła, więc nie rozumieją już przesłania, które hasło „stało się uważane za szkodliwe” przekazane docelowym odbiorcom w momencie jego wprowadzenia.
Hasła, których nie rozumiemy, nie są zbyt pouczające. Prawdopodobnie najlepiej zapomnieć o takich hasłach. Takie hasła nie pomagają.
Jednak to konkretne hasło „Goto uważane za szkodliwe” przyjęło własne nieumarłe życie.
Czy nie można nadużywać? Odpowiedź: jasne, ale co z tego? Praktycznie każdy element programowania może być nadużywany. Na
bool
przykład pokorni są wykorzystywani częściej niż niektórzy z nas chcieliby w to uwierzyć.Dla kontrastu nie pamiętam, żeby spotkałem się z jednym faktycznym przypadkiem znęcania się nad Goto od 1990 roku.
Największym problemem związanym z goto jest prawdopodobnie nie techniczny, ale społeczny. Programiści, którzy nie wiedzą zbyt wiele, czasami wydają się czuć, że wycofanie goto sprawia, że brzmią inteligentnie. Od czasu do czasu będziesz musiał zadowolić takich programistów. Takie jest życie.
Najgorszą rzeczą w goto dzisiaj jest to, że nie jest wystarczająco używana.
źródło
Zainteresowany dodaniem odpowiedzi przez Jaya Ballou, dodam 0,02 £. Gdyby Bruno Ranschaert jeszcze tego nie zrobił, wspomniałbym o artykule Knutha „Programowanie strukturalne z oświadczeniami GOTO”.
Jedną rzeczą, o której nie widziałem, jest rodzaj kodu, który, choć nie jest tak powszechny, był nauczany w podręcznikach Fortrana. Rzeczy takie jak rozszerzony zakres pętli DO i podprogramy o otwartym kodzie (pamiętaj, że byłby to Fortran II lub Fortran IV lub Fortran 66 - nie Fortran 77 lub 90). Istnieje co najmniej szansa, że szczegóły składniowe są niedokładne, ale pojęcia powinny być wystarczająco dokładne. Fragmenty w każdym przypadku znajdują się w jednej funkcji.
Zwróć uwagę, że doskonała, ale przestarzała (i wyczerpana) książka „ The Elements of Programming Style, 2nd Edn ” autorstwa Kernighan & Plauger zawiera kilka rzeczywistych przykładów nadużywania GOTO w programowaniu podręczników swojej epoki (koniec lat 70.). Poniższy materiał nie pochodzi jednak z tej książki.
Rozszerzony zasięg dla pętli DO
Jednym z powodów takich nonsensów była dobra, staromodna karta uderzeniowa. Można zauważyć, że etykiety (ładnie spoza sekwencji, ponieważ był to styl kanoniczny!) Znajdują się w kolumnie 1 (w rzeczywistości musiały być w kolumnach 1-5), a kod znajduje się w kolumnach 7-72 (kolumna 6 była kontynuacją kolumna znaczników). Kolumny 73-80 otrzymałyby numer sekwencyjny, a były maszyny, które sortowałyby talie kart dziurkaczy według kolejności numerów sekwencyjnych. Jeśli masz program na sekwencyjnych kartach i potrzebujesz dodać kilka kart (linii) do środka pętli, będziesz musiał ponownie wszystko uruchomić po tych dodatkowych liniach. Jeśli jednak zastąpisz jedną kartę GOTO, możesz uniknąć ponownego szeregowania wszystkich kart - po prostu włożyłeś nowe karty na końcu procedury z nowymi numerami sekwencji. Uważaj to za pierwszą próbę „zielonego przetwarzania”
Och, możesz też zauważyć, że oszukuję i nie krzyczę - Fortran IV napisano normalnie wielkimi literami.
Podprogram o otwartym kodzie
GOTO między etykietami 76 i 54 jest wersją obliczonego goto. Jeśli zmienna i ma wartość 1, przejdzie do pierwszej etykiety na liście (123); jeśli ma wartość 2, jest drugi i tak dalej. Fragment od 76 do obliczonego goto jest podprogramem o otwartym kodzie. Był to fragment kodu wykonywany raczej jak podprogram, ale zapisany w treści funkcji. (Fortran miał również funkcje instrukcji - które były funkcjami osadzonymi, które pasowały do jednej linii).
Były gorsze konstrukcje niż obliczone goto - można przypisać etykiety do zmiennych, a następnie użyć przypisanego goto. Goto przypisane do Goo mówi mi, że został usunięty z Fortran 95. Podejmij wyzwanie dla rewolucji w programowaniu strukturalnym, o której można powiedzieć, że rozpoczęła się publicznie listem lub artykułem „GOTO za szkodliwe” Dijkstry.
Bez pewnej wiedzy na temat tego, co zostało zrobione w Fortranie (i w innych językach, z których większość słusznie się pomogła), trudno jest nam, nowicjuszom, zrozumieć zakres problemu, z którym borykał się Dijkstra. Cholera, zacząłem programować dopiero dziesięć lat po opublikowaniu tego listu (ale miałem nieszczęście zaprogramować w Fortran IV).
źródło
goto
„na wolności”, pytanie Wanted: Working Bose-Hibbard Sort Algorytm pokazuje jakiś kod (Algol 60) opublikowany w 1963 roku. Oryginalny układ nie jest zgodny z nowoczesnymi standardami kodowania. Wyjaśniony (wcięty) kod jest wciąż dość nieprzenikniony. Tegoto
oświadczenia nie robić zrobić to (bardzo) trudno zrozumieć, co algorytm jest do.Nie ma takich rzeczy, jak GOTO uważane za szkodliwe .
GOTO jest narzędziem i, jak wszystkie narzędzia, można z niego korzystać i nadużywać .
Istnieje jednak wiele narzędzi w świecie programowania, które mają tendencję do częstszego wykorzystywania niż używania , a GOTO jest jednym z nich. instrukcja Z Delphi jest kolejna.
Osobiście nie używam żadnego z typowych kodów , ale miałem dziwne użycie GOTO i WITH, które były uzasadnione, a alternatywne rozwiązanie zawierałoby więcej kodu.
Najlepszym rozwiązaniem byłoby, aby kompilator po prostu ostrzegł cię, że słowo kluczowe zostało skażone , i będziesz musiał umieścić kilka instrukcji pragma wokół instrukcji, aby pozbyć się ostrzeżeń.
To tak, jakby powiedzieć dzieciom, żeby nie biegały nożyczkami . Nożyczki nie są złe, ale niektóre z nich mogą nie być najlepszym sposobem na utrzymanie zdrowia.
źródło
goto
słowo kluczowe zostało usunięte z C #, koncepcja „skocz tutaj” wciąż istnieje w IL. Nieskończoną pętlę można łatwo zbudować bez słowa kluczowego goto. Jeśli ten brak gwarancji, że wywołany kod zwróci, Twoim zdaniem, oznacza „niezdolność do rozumowania o kodzie”, to powiedziałbym, że nigdy nie mieliśmy takiej możliwości.goto
C # nie jest prawdziwym „goto” w pierwotnym znaczeniu tego słowa. Jest to znacznie słabsza wersja, która pozwala tylko przeskakiwać w obrębie funkcji. W sensie, w którym używam „goto”, można skakać gdziekolwiek w trakcie procesu. Więc chociaż C # ma słowo kluczowe „goto”, prawdopodobnie nigdy nie było, prawdziwe goto. Tak, prawdziwe goto jest dostępne na poziomie IL, w taki sam sposób, jak w przypadku kompilacji dowolnego języka aż do asemblera. Ale programista jest przed tym chroniony, nie może go używać w normalnych okolicznościach, więc się nie liczy.Nigdy tak nie było, o ile potrafiłeś samodzielnie myśleć.
źródło
Odkąd zacząłem robić kilka rzeczy w jądrze Linuksa, gotos nie przeszkadza mi tak bardzo jak kiedyś. Na początku byłem trochę przerażony, widząc, że (ludzie z jądra) dodali gotos do mojego kodu. Od tego czasu przyzwyczaiłem się do używania gotów, w niektórych ograniczonych kontekstach, i od czasu do czasu używam ich osobiście. Zazwyczaj jest to goto, które przeskakuje na koniec funkcji, aby wykonać jakieś czyszczenie i wyskoczyć, zamiast powielać to samo czyszczenie i ratowanie w kilku miejscach funkcji. I zazwyczaj nie jest to coś wystarczająco dużego, aby przekazać inną funkcję - np. Uwolnienie niektórych zmiennych lokalnych (k) malloc'ów jest typowym przypadkiem.
Napisałem kod, który używał setjmp / longjmp tylko raz. Było to w programie sekwencera perkusyjnego MIDI. Odtwarzanie odbyło się w oddzielnym procesie od wszystkich interakcji użytkownika, a proces odtwarzania wykorzystał pamięć współdzieloną z procesem interfejsu użytkownika, aby uzyskać ograniczone informacje potrzebne do odtworzenia. Gdy użytkownik chciał zatrzymać odtwarzanie, proces odtwarzania po prostu wykonał longjmp „od początku”, aby rozpocząć od nowa, zamiast skomplikowanego odwijania gdziekolwiek to się dzieje, gdy użytkownik chciał, aby się zatrzymał. Działało świetnie, było proste i nigdy nie miałem z tym żadnych problemów ani błędów.
setjmp / longjmp mają swoje miejsce - ale to miejsce prawdopodobnie nie będzie odwiedzane, ale od czasu do czasu.
Edycja: Właśnie spojrzałem na kod. Tak naprawdę to siglongjmp (), którego użyłem, a nie longjmp (nie to, że to wielka sprawa, ale zapomniałem, że siglongjmp nawet istniał.)
źródło
Jeśli piszesz maszynę wirtualną w C, okazuje się, że używając gotowych obliczeń (gcc):
działa znacznie szybciej niż konwencjonalny przełącznik wewnątrz pętli.
źródło
&&op_inc
na pewno się nie kompiluje, ponieważ (po lewej)&
oczekuje wartości, ale (po prawej)&
daje wartość.Ponieważ
goto
może być stosowany do mylącego metaprogramowaniaGoto
jest zarówno wyrażeniem kontrolnym wysokiego, jak i niskiego poziomu , w wyniku czego po prostu nie ma odpowiedniego wzorca projektowego odpowiedniego dla większości problemów.To niskiego poziomu w tym sensie, że jest prymitywny goto operacja, która implementuje coś jak wyżej
while
lubforeach
czy coś.Jest to wysoki poziom w tym sensie, że gdy jest używany w określony sposób, pobiera kod, który wykonuje się w przejrzystej sekwencji, w sposób nieprzerwany, z wyjątkiem strukturalnych pętli, i zmienia go w logikę, która przy wystarczającej liczbie
goto
s jest chwytaniem - torba logiki jest dynamicznie składana.Jest więc prozaiczna i zła strona
goto
.Prosaic bok jest skierowany ku górze, wskazując goto może stosować całkowicie wystarczającą pętlę i skierowaną w dół goto potrafi doskonale rozsądne
break
lubreturn
. Oczywiście rzeczywistywhile
,break
lubreturn
byłby o wiele bardziej czytelny, ponieważ biedny człowiek nie musiałby symulować efektugoto
, aby uzyskać duży obraz. Ogólnie zły pomysł.Strona zła obejmuje rutynę polegającą na tym, że nie używa się goto na chwilę, przerywa lub wraca, ale używa go do tak zwanej logiki spaghetti . W tym przypadku szczęśliwy deweloper goto buduje fragmenty kodu z labiryntu goto, a jedynym sposobem na zrozumienie go jest symulacja go mentalnie jako całości, strasznie męczące zadanie, gdy jest wiele goto. Wyobraź sobie trud obliczenia kodu, w którym
else
nie jest on dokładnie odwrotnością tegoif
, gdzie zagnieżdżoneif
s mogą pozwolić na niektóre rzeczy, które zostały odrzucone przez zewnętrzneif
, itp.Wreszcie, aby naprawdę omówić ten temat, należy zauważyć, że zasadniczo wszystkie wczesne języki, z wyjątkiem Algola, początkowo uzależniły tylko pojedyncze stwierdzenia od swoich wersji
if-then-else
. Tak więc jedynym sposobem na wykonanie bloku warunkowego byłogoto
obejście go za pomocą odwrotnego warunkowego. Szalony, wiem, ale przeczytałem kilka starych specyfikacji. Pamiętaj, że pierwsze komputery zostały zaprogramowane w binarnym kodzie maszynowym, więc przypuszczam, że jakikolwiek HLL był ratownikiem; Myślę, że nie byli zbyt wybredni, jeśli chodzi o to, jakie dokładnie funkcje HLL mają.Powiedziawszy to, co zwykle wkładałem
goto
w każdy program, który napisałem „tylko po to, by zirytować purystów” .źródło
Odmawianie programistom użycia instrukcji GOTO jest jak mówienie stolarzowi, aby nie używał młotka, ponieważ może on uszkodzić ścianę, gdy wbija gwóźdź. Prawdziwy programista wie, jak i kiedy używać GOTO. Podążałem za niektórymi z tak zwanych „programów strukturalnych”. Widzę taki kod Horrida, aby uniknąć używania GOTO, aby móc strzelać do programisty. Ok, w obronie drugiej strony, widziałem też trochę prawdziwego kodu spaghetti i ci programiści też powinni zostać zastrzeleni.
Oto tylko jeden mały przykład kodu, który znalazłem.
-----------------------LUB----------------------
źródło
goto
- i wie, dlaczego . Unikanie konstrukcji języka tabu, ponieważ $ program_guru tak powiedział, to jest właśnie definicja programowania kultowego.„W tym linku http://kerneltrap.org/node/553/2131 ”
Jak na ironię, wyeliminowanie goto wprowadziło błąd: połączenie blokady zostało pominięte.
źródło
Oryginalny artykuł należy traktować jako „bezwarunkowe GOTO uważane za szkodliwe”. W szczególności opowiadał się za formą programowania opartą na konstrukcjach warunkowych (
if
) i iteracyjnych (while
), a nie testowaniem i przeskakiwaniem typowym dla wczesnego kodu.goto
jest nadal przydatny w niektórych językach lub okolicznościach, w których nie istnieje odpowiednia struktura kontroli.źródło
O jedynym miejscem zgadzam Goto mógł być wykorzystane, to kiedy musisz poradzić sobie z błędami, a każdy konkretny punkt, w którym pojawia się błąd, wymaga specjalnej obsługi.
Na przykład, jeśli chwytasz zasoby i używasz semaforów lub muteksów, musisz chwytać je w kolejności i zawsze powinieneś zwalniać je w odwrotny sposób.
Niektóre kody wymagają bardzo dziwnego wzorca chwytania tych zasobów i nie można po prostu napisać łatwej w utrzymaniu i zrozumiałej strukturze sterowania, aby poprawnie obsłużyć zarówno chwytanie, jak i zwalnianie tych zasobów, aby uniknąć impasu.
Zawsze można to zrobić poprawnie bez goto, ale w tym przypadku i kilku innych Goto jest w rzeczywistości lepszym rozwiązaniem przede wszystkim dla czytelności i łatwości konserwacji.
-Adam
źródło
Jednym z nowoczesnych zastosowań GOTO jest kompilator C # do tworzenia automatów stanów dla enumeratorów zdefiniowanych przez zwrot z wydajności.
GOTO jest czymś, z czego powinni korzystać kompilatorzy, a nie programiści.
źródło
goto
. Tam, gdzie moglibyśmy użyćgoto
w maszynie stanu zakodowanej ręcznie do implementacji modułu wyliczającego, możemy po prostu użyćyield
zamiast tego.Dopóki C i C ++ (pośród innych sprawców) nie oznaczą przerw i kontynuuje, goto będzie nadal odgrywać pewną rolę.
źródło
Gdyby samo GOTO było złe, kompilatory byłyby złe, ponieważ generują JMP. Jeśli przeskakiwanie do bloku kodu, szczególnie podążającego za wskaźnikiem, byłoby z natury złe, instrukcja POWROTU byłaby zła. Przeciwnie, zło może być nadużywane.
Czasami musiałem pisać aplikacje, które musiały śledzić pewną liczbę obiektów, w których każdy obiekt musiał reagować na skomplikowaną sekwencję stanów w odpowiedzi na zdarzenia, ale całość była zdecydowanie jednowątkowa. Typowa sekwencja stanów, jeśli jest reprezentowana w pseudokodzie, to:
Jestem pewien, że to nie jest nowe, ale sposób, w jaki obsługiwałem to w C (++), to zdefiniowanie niektórych makr:
Następnie (zakładając, że stan jest początkowo 0), ustrukturyzowana maszyna stanów powyżej zamienia się w kod strukturalny:
Z pewną odmianą może być CALL i RETURN, więc niektóre maszyny stanowe mogą działać jak podprogramy innych maszyn stanowych.
Czy to niezwykłe? Tak. Czy zajmuje to trochę nauki ze strony opiekuna? Tak. Czy ta nauka się opłaca? Chyba tak. Czy można tego dokonać bez GOTO, które skaczą w bloki? Nie.
źródło
Unikam tego, ponieważ współpracownik / menedżer bez wątpienia zakwestionuje jego użycie w recenzji kodu lub kiedy natknie się na niego. Chociaż wydaje mi się, że ma to zastosowanie (na przykład przypadek obsługi błędów) - popełnisz błąd innego programisty, który będzie miał z tym jakiś problem.
To nie jest tego warte.
źródło
Byłem zmuszony użyć goto, ponieważ dosłownie nie mogłem wymyślić lepszego (szybszego) sposobu na napisanie tego kodu:
Miałem złożony obiekt i musiałem wykonać na nim pewną operację. Jeśli obiekt był w jednym stanie, mógłbym wykonać szybką wersję operacji, w przeciwnym razie musiałbym wykonać wolną wersję operacji. Chodziło o to, że w niektórych przypadkach, w trakcie powolnej operacji można było zrozumieć, że można to zrobić przy szybkiej operacji.
Było to w kawałku kodu interfejsu użytkownika w czasie rzeczywistym, więc szczerze sądzę, że GOTO było tutaj uzasadnione.
Hugo
źródło
Niemal we wszystkich sytuacjach, w których można użyć goto, możesz zrobić to samo, używając innych konstrukcji. I tak kompilator używa Goto.
Osobiście nigdy nie używam tego jawnie, nigdy nie muszę.
źródło
Jednej rzeczy, której nie widziałem w żadnej z odpowiedzi tutaj, jest to, że rozwiązanie „goto” jest często bardziej wydajne niż jedno z często wymienianych rozwiązań programowania strukturalnego.
Rozważ przypadek wielu zagnieżdżonych pętli, w którym użycie „goto” zamiast kilku
if(breakVariable)
sekcji jest oczywiście bardziej wydajne. Rozwiązanie „Włącz pętle w funkcję i użyj return” jest często całkowicie nieracjonalne. W prawdopodobnym przypadku, gdy pętle używają zmiennych lokalnych, musisz teraz przekazać je wszystkie przez parametry funkcji, potencjalnie radząc sobie z mnóstwem dodatkowych bólów głowy, które z tego wynikają.Rozważmy teraz przypadek czyszczenia, z którego korzystałem dość często i jest tak powszechny, że prawdopodobnie był odpowiedzialny za strukturę try {} catch {} niedostępną w wielu językach. Liczba kontroli i dodatkowych zmiennych wymaganych do osiągnięcia tego samego jest znacznie gorsza niż jedna lub dwie instrukcje wykonania skoku, i znowu, dodatkowe rozwiązanie funkcji wcale nie jest rozwiązaniem. Nie możesz mi powiedzieć, że jest to łatwiejsze w zarządzaniu lub bardziej czytelne.
Teraz przestrzeń kodu, użycie stosu i czas wykonania mogą w wielu sytuacjach nie mieć wystarczającego znaczenia dla wielu programistów, ale gdy jesteś w środowisku osadzonym z tylko 2 KB miejsca do pracy, 50 bajtów dodatkowych instrukcji, aby uniknąć jednego jasno określonego „goto” jest po prostu śmieszne, i nie jest to tak rzadka sytuacja, jak uważa wielu programistów wysokiego szczebla.
Stwierdzenie, że „goto jest szkodliwe”, było bardzo pomocne w przejściu na programowanie strukturalne, nawet jeśli zawsze było to nadmierne uogólnienie. W tym momencie wszyscy słyszeliśmy to na tyle, aby uważać na używanie go (tak jak powinniśmy). Gdy jest to oczywiście odpowiednie narzędzie do pracy, nie musimy się go bać.
źródło
Możesz go użyć do zerwania z głęboko zagnieżdżonej pętli, ale przez większość czasu twój kod może zostać przekształcony w czystszy bez głęboko zagnieżdżonych pętli.
źródło