goto
wordt bijna universeel ontmoedigd. Is het gebruik van deze verklaring ooit de moeite waard?
Reacties
Antwoord
Dit is verschillende keren besproken op Stack Overflow, en Chris Gillum vat de mogelijke toepassingen van goto
samen:
Netjes een functie verlaten
Vaak kun je in een functie bronnen toewijzen en moet je op meerdere plaatsen afsluiten. Programmeurs kunnen hun code vereenvoudigen door de code voor het opschonen van bronnen aan het einde van de functie te plaatsen, alle ” exitpunten ” van de functie zouden naar het opruimlabel. Op deze manier hoeft u “geen opschooncode te schrijven op elk ” exitpunt ” van de functie.
Geneste lussen verlaten
Als je in een geneste lus zit en je uit all loops, kan een goto dit veel schoner en eenvoudiger maken dan break-statements en if-checks.
Prestatieverbeteringen op laag niveau
Dit is alleen geldig in perf-kritische code, maar goto-instructies worden zeer snel uitgevoerd en kunnen je een boost geven als je door een functie gaat. Dit is echter een tweesnijdend zwaard, omdat een compiler doorgaans geen code kan optimaliseren die gotos bevat.
Ik zou zeggen, zoals vele anderen zouden beweren , dat in al deze gevallen het gebruik van goto
wordt gebruikt als een middel om uit een hoek te komen waarin iemand zichzelf heeft gecodeerd, en dit is over het algemeen een symptoom van code die kan worden geherstructureerd .
Reacties
- Het eerste probleem wordt heel netjes opgelost door
finally
blokken in moderne talen, en de tweede wordt opgelost door gelabeldbreak
s. Als je ‘ echter vasthoudt aan C,goto
is vrijwel de enige manier om deze problemen op een elegante manier op te lossen. - Zeer goede punten. Ik vind het leuk hoe Java het mogelijk maakt om uit meerdere niveaus van lussen te breken
- @Chinmay – tenslotte alleen blokken zijn van toepassing op 1) moderne talen die ze hebben en b) u kunt de overhead tolereren (het afhandelen van uitzonderingen heeft wel overhead. ) Dat wil zeggen, het gebruik van
finally
is alleen geldig onder die voorwaarden. Er zijn zeer zeldzame, maar geldige situaties waarin een goto de juiste weg is. - Oké mensen … wat is in hemelsnaam het verschil tussen
break 3
ofbreak myLabel
engoto myLabel
. Oh dat ‘ klopt precies met het trefwoord. Als jebreak
,continue
of een vergelijkbaar zoekwoord gebruikt, gebruik je eigenlijk eengoto
(Als ufor, while, foreach, do/loop
gebruikt, gebruikt u een voorwaardelijke goto.) - Over prestaties op laag niveau – het gedrag van een moderne processor is misschien moeilijk te voorspellen (pijplijn, uitvoering buiten de bestelling), dus waarschijnlijk in 99% van de gevallen is het het niet waard of kan het zelfs langzamer zijn. @MatthewWhited: Scoping. Als je scope op een willekeurig punt invoert, is het niet duidelijk (voor de mens) welke constructors moeten worden genoemd (het probleem doet zich ook voor in C).
Answer
Controlestroomconstructies op hoger niveau komen meestal overeen met concepten in het probleemdomein. Een if / else is een beslissing op basis van een bepaalde voorwaarde. Een lus zegt om een actie herhaaldelijk uit te voeren. Zelfs een break-statement zegt: “we deden dit herhaaldelijk, maar nu moeten we stoppen”.
Een go-statement daarentegen komt overeen met een concept in het lopende programma, niet in het probleem domein. Er staat dat de uitvoering moet worden voortgezet op een gespecificeerd punt in het programma . Iemand die de code leest, moet afleiden wat dat betekent met betrekking tot het probleemdomein.
Natuurlijk kunnen alle constructies op een hoger niveau worden gedefinieerd in termen van gotos en eenvoudige voorwaardelijke vertakkingen . Dat betekent niet dat ze alleen maar vermomd zijn. Beschouw ze als beperkte gotos – en het zijn de beperkingen die ze nuttig maken. Een break-statement wordt geïmplementeerd als een sprong naar het einde van de omsluitende lus, maar het is beter als die als geheel op de lus werken.
Als al het andere gelijk is, is code waarvan de structuur overeenkomt met die van het probleemdomein gemakkelijker te lezen en te onderhouden.
Er zijn geen gevallen waarin een goto-statement is absoluut vereist (er is “s een theorema voor dat effect), maar er zijn gevallen waarin dit de minst slechte oplossing kan zijn. Die gevallen variëren van taal naar taal, afhankelijk van wat constructies op een hoger niveau de taal ondersteunt.
In C denk ik bijvoorbeeld dat er drie basisscenarios zijn waarin een goto geschikt is.
- Het doorbreken van een geneste lus. Dit zou niet nodig zijn als de taal een gelabelde break-instructie had.
- Uit een stuk code (meestal een functie-body) springen in het geval van een fout of een andere onverwachte gebeurtenisDit zou niet nodig zijn als de taal uitzonderingen had.
- Implementatie van een expliciete eindige toestandsmachine. In dit geval (en, denk ik, alleen in dit geval) komt een goto rechtstreeks overeen met een concept in het probleemdomein, waarbij het overgaat van de ene staat naar een gespecificeerde andere staat, waar de huidige staat wordt weergegeven door welk codeblok momenteel wordt uitgevoerd .
Aan de andere kant kan een expliciete eindige-toestandsmachine ook worden geïmplementeerd met een switch-instructie in een lus. Dit heeft als voordeel dat elke staat op dezelfde plaats in de code begint, wat handig kan zijn voor bijvoorbeeld debuggen.
Het belangrijkste gebruik van een goto in een redelijk moderne taal (een die ondersteunt if / else en loops) is om een besturingsstroomconstructie te simuleren die “ontbreekt in de taal.
Opmerkingen
- Dit is eigenlijk het beste antwoord tot nu toe – nogal verrassend, voor een vraag die anderhalf jaar oud is. 🙂
- +1 tot ” beste antwoord tot nu toe “. — ” Het belangrijkste gebruik van een goto in een redelijk moderne taal (een die if / else en loops ondersteunt) is het simuleren van een controlestroom construeer dat ‘ s ontbreekt in de taal. ”
- In switch-statement status machine, elke schrijf naar de controlewaarde is echt een
goto
. SSSM ‘ s zijn vaak goede structuren om te gebruiken, omdat ze parate de SM-status van de uitvoeringsconstructie, maar ze ‘ elimineren ” gotos “. - ” Als al het andere gelijk is, is code waarvan de structuur overeenkomt met die van het probleemdomein meestal gemakkelijker te lezen en te onderhouden. ” Ik ‘ ken dit al heel lang volledig, maar miste de woorden om het zo nauwkeurig over te brengen dat andere programmeurs kunnen en zullen het ook echt begrijpen. Bedankt hiervoor.
- Het ” gestructureerde programma-theorema ” amuseert me, omdat het de neiging heeft om duidelijk de wijs erop dat het gebruik van gestructureerde programmeerinstructies om een goto te emuleren veel minder leesbaar is dan alleen het gebruik van een goto!
Answer
Het hangt zeker af van de programmeertaal. De belangrijkste reden dat goto
controversieel is geweest, is vanwege de nadelige gevolgen die optreden wanneer de compiler u het te royaal laat gebruiken. Er kunnen zich bijvoorbeeld problemen voordoen als je goto
op zon manier kunt gebruiken dat je nu toegang hebt tot een niet-geïnitialiseerde variabele, of erger nog, om een andere methode te gebruiken en te knoeien met de aanroep stapel. Het zou de verantwoordelijkheid van de compiler moeten zijn om onzinnige controlestroom niet toe te staan.
Java heeft geprobeerd dit probleem “op te lossen” door goto
helemaal niet toe te staan. Java laat je echter toe return
binnen een finally
blok te gebruiken en zo een exception onbedoeld te laten inslikken.Hetzelfde probleem is er nog steeds: de compiler doet zijn werk niet. Het verwijderen van goto
uit de taal heeft dit niet opgelost.
In C # is goto
net zo veilig als break
, continue
, try/catch/finally
en return
. Het laat je niet toe niet-geïnitialiseerde variabelen te gebruiken, het laat je niet uit een eindblok springen, enz. De compiler zal klagen. Dit komt omdat het het echte probleem oplost, wat zoals ik al zei een onzinnige controlestroom is. goto
annuleert niet op magische wijze definitieve toewijzingsanalyse en andere redelijke compilercontroles.
Opmerkingen
- Uw punt is dat C # ‘ s
goto
niet slecht is? Als dit het geval is, is dat het geval voor elke routinematig gebruikte moderne taal met eengoto
-constructie, niet alleen C # …
Antwoord
Ja. Als je lussen meerdere niveaus diep zijn genest, is goto
de enige manier om op een elegante manier uit een binnenste lus te breken. De andere optie is om een vlag in te stellen en uit elke lus te breken als die vlag aan een voorwaarde voldoet. Dit is echt lelijk en behoorlijk foutgevoelig. In deze gevallen is goto
gewoon beter.
Natuurlijk doen Java-instructies met het label break
hetzelfde ding, maar zonder je toe te staan naar een willekeurig punt in de code te springen, wat het probleem netjes oplost zonder de dingen toe te staan die goto
slecht maken.
Opmerkingen
- goto is nooit een elegant antwoord. Wanneer je loops meerdere niveaus diep zijn genest, is je probleem dat je er niet in geslaagd bent om je code te ontwerpen om de multinested loops te vermijden. Procedure aanroepen zijn NIET de vijand. (Lees de ” Lambda: The Ultimate … ” papers.) Een goto gebruiken om uit meerdere geneste lussen te breken levels deep is het plaatsen van een pleister op een open meervoudige breuk: het mag dan eenvoudig zijn, maar het is niet ‘ het juiste antwoord.
- En natuurlijk is nooit het vreemde geval wanneer diep geneste lussen nodig zijn? Een goede programmeur zijn isn t alleen om de regels te volgen, maar ook om te weten wanneer je ze moet overtreden.
- @ JohnR.Strohm Zeg nooit nooit. Als je termen als ” nooit ” gebruikt bij het programmeren, heb je ‘ duidelijk niet behandeld met hoekgevallen, optimalisatie, resource contraints, etc. In diep geneste lussen is goto inderdaad de meest zuivere, elegante manier om de lussen te verlaten. Maakt ‘ niet uit hoeveel u ‘ uw code hebt geherstructureerd.
- @ JohnR.Strohm: tweede meest gemiste functie bij het overschakelen van VB.NET naar C #: de
Do
lus. Waarom? Omdat ik de ene lus die een diepe pauze nodig heeft, kan veranderen in eenDo
lus enExit Do
kan typen en daar ‘ s neeGoTo
. Geneste lussen vinden de hele tijd plaats. Het doorbreken van de stapels gebeurt soms. - @ JohnR.Strohm De enige reden waarom je ” goto zegt, is nooit een elegant antwoord ” is omdat je hebt besloten dat goto nooit een elegant antwoord is, en daarom kan elke oplossing die goto gebruikt geen elegant antwoord zijn.
Antwoord
Het grootste deel van de ontmoediging komt van een soort “religie” die is gecreëerd door God Djikstra die in het begin van de jaren 60 overtuigend was over zijn willekeurige macht om :
- spring ergens in welk codeblok dan ook
- functie die niet vanaf het begin wordt uitgevoerd
- lussen die niet vanaf het begin worden uitgevoerd
- overgeslagen variabele initialisatie
- spring weg van welk codeblok dan ook zonder enige mogelijke opschoning.
Dit heeft niets meer te maken met de goto
verklaring van de moderne talen, waarvan het bestaan louter is om de cr te ondersteunen eation van codestructuren anders dan de taal die wordt aangeboden.
Met name het eerste hoofdpunt hierboven is meer toegestaan en het tweede wordt opgeschoond (als u goto
uit een blok de stapel wordt correct afgewikkeld en alle juiste destructors worden aangeroepen)
U kunt dit antwoord verwijzen om een idee te hebben van hoe zelfs code niet het gebruik van goto kan onleesbaar zijn. Het probleem zit hem niet in zichzelf, maar het slechte gebruik ervan.
Ik kan een heel programma schrijven zonder if
te gebruiken, alleen for
. Het zal natuurlijk niet goed leesbaar, onhandig en onnodig gecompliceerd lijken.
Maar het probleem is niet for
. Ik ben het.
Dingen als break
, continue
, throw
, bool needed=true; while(needed) {...}
, enz. nemen niet meer dan maskerade goto
om te ontsnappen aan de kromzwaarden van de Djikstrarische fanaten, dat – Vijftig jaar na de uitvinding van moderne talen, willen ze nog steeds hun gevangenen. Ze vergaten waar Djikstra het over had, ze onthouden alleen de titel van zijn briefje (GOTO werd als schadelijk beschouwd, en het was niet eens zijn eigen titel: het werd veranderd door de redacteur) en beschuldigden en bash, bash en beschuldigden elke constructie met die 4 letter in volgorde geplaatst.
Het is 2011: het is tijd om te begrijpen dat goto
iets te maken heeft met de GOTO
statement waar Djikstra overtuigend over was.
Reacties
- ” Dingen zoals pauze, ga door , gooien, bool nodig = waar; while (nodig) {…}, enz. zijn niet meer dan een maskerade ga naar ” Ik ben het daar niet mee eens ‘. Ik zou liever hebben dat ” zaken zoals pauze enz. beperkt zijn, ga naar “, of iets dergelijks. Het grootste probleem met goto is dat het meestal te krachtig is. In de mate dat de huidige goto minder krachtig is dan Dijkstra ‘ s, vind ik je antwoord prima.
- @MuhammadAlkarouri: Helemaal mee eens. U heeft zojuist een betere formulering gevonden die precies mijn concept uitdrukt. Mijn punt is dat die beperking soms niet van toepassing kan zijn en het soort beperking dat je nodig hebt, is niet in de taal. Dan is een meer ” krachtig ” ding, minder gespecialiseerd, wat u in staat stelt om te omzeilen. De Java
break n
is bijvoorbeeld niet beschikbaar in C ++, dusgoto escape
, zelfs alsescape
hoeft niet net buiten de n-ple-lus te zijn.
Answer
Af en toe ga je hierheen of daar, zolang het lokaal is voor een functie, de leesbaarheid zelden significant schaadt. Het heeft er vaak baat bij door de aandacht te vestigen op het feit dat er iets ongewoons aan de hand is in deze code dat het gebruik van een ietwat ongebruikelijke besturingsstructuur vereist .
Als (lokale) goto s de leesbaarheid aanzienlijk schaden, dan is dat meestal een teken dat de functie die de goto bevat te complex is geworden.
De laatste goto die ik in een stuk C-code was om een paar in elkaar grijpende lussen te bouwen. Het past niet in de normale definitie van “acceptabel” ga naar gebruik, maar de functie werd daardoor aanzienlijk kleiner en duidelijker. Om de goto te vermijden zou een bijzonder rommelige schending van DRY nodig zijn geweest.
Opmerkingen
- Het antwoord hierop wordt heel kernachtig vermeld in de oude ” Lay ‘ s Aardappelchips ” slogan: ” Wed dat je ‘ er niet één kunt eten “. In je voorbeeld heb je twee ” in elkaar grijpende ” (wat dat ook betekent, en ik ‘ m wedden dat het geen ‘ t mooie) lussen is, en de goto gaf je een goedkope uitval. Hoe zit het met de klusjesman, die die code moet aanpassen nadat je door een bus bent aangereden? Zal de goto zijn leven gemakkelijker of moeilijker maken? Moeten deze twee lussen opnieuw worden bekeken?
Antwoord
Ik denk dat dit hele probleem een kwestie van blaffen is geweest de verkeerde boom.
GOTO als zodanig lijkt mij niet problematisch, maar het is eerder een symptoom van een daadwerkelijke zonde: spaghetticode.
Als de GOTO grote kruising van stroomregelleidingen dan is het slecht, periode. Als het geen stroomregelleidingen kruist, is het onschadelijk. In de grijze zone ertussen hebben we zaken als loop bailouts, er zijn nog steeds enkele talen die geen constructies hebben toegevoegd die alle legitieme grijze gevallen dekken.
Het enige geval dat ik merkte dat ik het daadwerkelijk gebruik in vele jaren is het geval van de lus waar het beslissingspunt zich in het midden van de lus bevindt. Je blijft achter met ofwel gedupliceerde code, een vlag of een GOTO. Ik vind de GOTO-oplossing de beste van de drie. Er is hier geen kruising van flow control-lijnen, het is onschadelijk.
Opmerkingen
- Het geval waarnaar u verwijst, wordt soms “loop and a half” of “N plus one half loop” genoemd en het is een bekende use-case voor
goto
s die in een lus springen (als de taal dit toestaat; aangezien het andere geval, uit de lus springen in het midden, meestal triviaal is zondergoto
). - (Helaas, de meeste talen verbieden het om in een lus te springen.)
- @KonradRudolph: als je de ” lus ” met GOTO is er geen andere lusstructuur om in te springen.
- Ik zie
goto
als schreeuwen: THE CONTROL FLOW HIER DOET ‘ T FIT NORMAAL GESTRUCTUREERD PROGRAMMEREN PATRONEN . Omdat controlestromen die passen bij gestructureerde programmeerpatronen gemakkelijker te redeneren zijn dan die welke niet ‘ t zijn, moet men proberen om dergelijke patronen te gebruiken wanneer mogelijk; als de code wel in dergelijke patronen past, moet men ‘ t roepen dat het niet ‘ t. Aan de andere kant, in gevallen waarin code echt niet ‘ t in dergelijke patronen past, kan het beter zijn om erover te schreeuwen dan te doen alsof de code past terwijl het echt niet ‘ t. - @supercat Nou, stel je voor dat je voor jezelf een schema hebt geschreven, en dan blaast de wind het uit je handen. Volgens uw logica zou u het ‘ niet moeten ophalen, omdat het najagen van uw schema niet ‘ op uw schema stond.
Antwoord
Ja, de goto kan worden gebruikt om de ervaring van de ontwikkelaar ten goede te komen: http://adamjonrichardson.com/2012/02/06/long-live-the-goto-statement/
Echter, net als bij elke krachtige tool (pointers, meervoudige overerving, etc.), moet men gedisciplineerd worden het gebruiken. Het voorbeeld in de link gebruikt PHP, waardoor het gebruik van de goto-constructie wordt beperkt tot dezelfde functie / methode en de mogelijkheid wordt uitgeschakeld om in een nieuw besturingsblok te springen (bijv. Loop, instructie switch, enz.)
Answer
Hangt af van de taal. Het wordt bijvoorbeeld nog steeds veel gebruikt in Cobol-programmering. Ik heb ook gewerkt aan een Barionet 50-apparaat, waarvan de programmeertaal in de firmware een vroeg BASIC-dialect is waarvoor je natuurlijk Goto moet gebruiken.
Answer
goto
kan handig zijn bij het porten van legacy assembler-code naar C. In eerste instantie een instructie- door instructie conversie naar C, gebruikmakend van goto
als vervanging voor de assembler “s branch
instructie, kan een zeer snelle portering mogelijk maken.
Reacties
- Correct, maar een van de argumenten tegen
goto
s is dat ze compileroptimalisaties dwarsbomen. - @Sapphire_Brick: Veel compiler-optimalisaties zijn ontworpen rond bepaalde uitvoeringspatronen. Als de uit te voeren taak niet ‘ past in de ondersteunde uitvoeringspatronen, ” dwarsbomen van ” optimalisaties is mogelijk niet een slechte zaak zijn.
Antwoord
Ik zou nee willen zeggen. Ze moeten altijd worden vervangen door een tool die specifieker is voor het probleem waarvoor de goto wordt gebruikt om op te lossen (tenzij deze niet beschikbaar is in uw taal). Break-statements en uitzonderingen lossen bijvoorbeeld eerder opgeloste problemen op met lus-escaping en foutafhandeling.
Opmerkingen
- Ik ‘ zou beweren dat wanneer talen beide deze functies,
goto
ontbreekt doorgaans in die talen. - Maar is dat omdat ze ‘ heb je ze niet nodig, of omdat mensen denken dat ze ‘ ze niet nodig hebben?
- Je mening is onverdraagzaam. Er zijn veel gevallen waarin
goto
komt het dichtst in de buurt van de zeer problematische domeinsemantiek, al het andere zou een vuile hack zijn. - @ SK-logic: I don ‘ denk niet dat het woord ” onverdraagzaam ” betekent wat je denkt dat het betekent.
- @Keith,
onverdraagzaam toegewijd aan zijn of haar eigen meningen en vooroordelen ” – dat ‘ is wat ik hier consequent observeren, met deze geblinddoekte partij. ” Moeten altijd worden vervangen ” zijn fanatiek ‘ s woorden, tenminste. Niets dat in de buurt komt van een juiste, gezonde mening, maar gewoon pure onverdraagzaamheid. Dit ” altijd ” laat geen ruimte voor een alternatieve mening, zie je?
Antwoord
Ik zou nee zeggen. Als je de noodzaak vindt om GOTO te gebruiken, “wed ik dat het nodig is om de code opnieuw te ontwerpen.
Reacties
- Misschien, maar jij haven ‘ t heeft enige redenering gegeven
- Dijkstra heeft decennia geleden de redenering in detail gegeven.
- Just Dogma. Geen reacties. Opmerking: Djikstra is GEEN GELDIGE RESON MEER: het verwees naar de BASIC- of FORTRAN GOTO-instructie van de vroege ‘ 60s. Ze hebben niets te maken met de werkelijk bloedarmoede (vergeleken met de kracht van die) gots-s van vandaag.
- @EmilioGaravaglia Nou, het deel van zijn redenering dat vandaag nog steeds van toepassing is, is dat het ‘ s heel gemakkelijk is om spaghetticode te schrijven door veel te gebruiken voor veel fotos. Volgens die logica mogen we ‘ geen pointers gebruiken, omdat het gebruik van net zoveel pointers als
number of gotos needed to create problems
een vergelijkbare chaos zou creëren.
goto
is wat de cpu uiteindelijk doet, maar het werkt niet goed met wat mensen moeten begrijpen en abstraheren omdat er geen markering op het doel staat einde. Vergelijk met IntercalCOMEFROM
.goto
is natuurlijk niet vereist. Het is gewoon de meest rationele manier om ze in de imperatieve talen te implementeren, omdat het het dichtst bij de semantiek van de staatsovergang komt. En de bestemming kan behoorlijk ver van de bron verwijderd zijn, het zal de leesbaarheid niet belemmeren ‘. Mijn favoriete voorbeeld van zon code is D.E. Knuth ‘ s implementatie van het avonturenspel.