goto este aproape universal descurajat. Utilizează această afirmație merită vreodată?

Comentarii

  • xkcd.com/292
  • goto este ceea ce face CPU în cele din urmă, dar nu funcționează bine cu ceea ce oamenii trebuie să înțeleagă și să abstractizeze, deoarece nu există niciun semn pe țintă Sfârșit. Comparați cu Intercal COMEFROM.
  • @Thorbj ø rnRavnAndersen, ce mai înseamnă oamenii când ‘ vorbești despre tranziții de stare într-o mașină de stat? ‘ nu puteți vedea o asemănare? ” Accesați o stare dată „, ‘ Ce înseamnă și orice altceva nu ar fi altceva decât o complicație inutilă a unui lucru atât de banal. Și ce vrei să spui prin ” fără semn „? Eticheta este un astfel de semn.
  • @ SK-logic, depinde de cât de departe veți permite să apară ‘ s. Mașinile de stat nu necesită accesare pentru a fi implementate.
  • @Thorbj ø rnRavnAndersen, desigur goto nu este necesar. Este doar cel mai rațional mod de a le implementa în limbile imperative, deoarece este cel mai apropiat de semantica tranziției de stat. Iar destinația sa poate fi destul de departe de sursă, ‘ nu va împiedica lizibilitatea. Exemplul meu preferat de astfel de cod este D.E. Implementarea Knuth ‘ a jocului Adventure.

Răspuns

Acest lucru a fost discutat de mai multe ori pe Stack Overflow, iar Chris Gillum a rezumat posibilele utilizări ale goto :

Ieșirea curată a unei funcții

Adesea într-o funcție, puteți aloca resurse și trebuie să ieșiți în mai multe locuri. Programatorii își pot simplifica codul punând codul de curățare a resurselor la sfârșitul funcției, toate ” punctele de ieșire ” ale funcției ar merge eticheta de curățare. În acest fel, nu trebuie să scrieți cod de curățare la fiecare ” punct de ieșire ” al funcției.

Ieșirea buclelor imbricate

Dacă vă aflați într-o buclă imbricată și trebuie să ieșiți din all bucle, un pas poate face acest lucru mult mai curat și mai simplu decât instrucțiunile break și if-checks.

Îmbunătățiri de performanță la nivel scăzut

Acest lucru este valabil numai în codul perf-critic, dar instrucțiunile goto se execută foarte repede și vă pot oferi un impuls atunci când vă deplasați printr-o funcție. Cu toate acestea, aceasta este o sabie cu două tăișe, deoarece un compilator de obicei nu poate optimiza codul care conține gotos.

Eu aș argumenta, așa cum ar susține mulți alții , că în toate aceste cazuri, utilizarea goto este utilizată ca mijloc de a ieși dintr-un colț în care te-ai codificat și este, în general, un simptom al codului care ar putea fi refactorizat .

Comentarii

  • Prima problemă este rezolvată foarte bine prin blocurile finally în limbile moderne și al doilea este rezolvat prin etichetate break s. Dacă totuși rămâi ‘ blocat cu C, goto este cam singurul mod de a rezolva elegant aceste probleme.
  • Puncte foarte bune. Îmi place modul în care Java permite ieșirea din mai multe niveluri de bucle
  • @Chinmay – în cele din urmă numai blocuri se aplică 1) limbilor moderne care le au și b) puteți tolera cheltuielile generale (tratarea excepțiilor are o cheltuieli generale). ) Adică, utilizarea finally este valabilă numai în aceste condiții. Există situații foarte rare, dar valabile, în care o cale de urmat este calea de urmat.
  • Bine, oameni buni … care naiba este diferența dintre break 3 sau break myLabel și goto myLabel. Oh, ‘ este corect doar cuvântul cheie. Dacă utilizați break, continue sau un cuvânt cheie similar, sunteți de fapt folosind un goto (Dacă utilizați for, while, foreach, do/loop, utilizați un mod condiționat.)
  • Despre performanțe de nivel scăzut – comportamentul procesorului modern ar putea fi greu de prezis (conductă, execuție în afara comenzii) deci probabil în 99% din cazuri nu merită sau chiar ar putea fi mai lent. @MatthewWhited: Scoping. Dacă introduceți domeniul de aplicare la un punct arbitrar, nu este clar (pentru om) ce constructori ar trebui să fie numiți (problema există și în C).

Răspuns

Construcțiile fluxului de control la nivel superior tind să corespundă conceptelor din domeniul problemei. Un if / else este o decizie bazată pe o anumită condiție. O buclă spune să efectuați o acțiune în mod repetat. Chiar și o declarație de pauză spune „făceam acest lucru în mod repetat, dar acum trebuie să ne oprim”.

O declarație goto, pe de altă parte, tinde să corespundă unui concept din programul care rulează, nu din domeniul problemei. Se spune să continuați executarea la un punct specific în program . Cineva care citește codul trebuie să deducă ce înseamnă asta cu privire la domeniul problemei.

Desigur, toate constructele de nivel superior pot fi definite în termeni de gotos și ramuri condiționale simple. . Asta nu înseamnă că ei sunt doar deghizați. Gândiți-vă la ele ca la restricționate gotos – și sunt „restricțiile care le fac utile. O instrucțiune break este implementată ca un salt la sfârșitul buclei de închidere, dar este mai bine gândit ca care funcționează pe ansamblu.

Toate celelalte fiind egale, codul a cărui structură reflectă cea a domeniului problemei tinde să fie mai ușor de citit și întreținut.

Nu există cazuri în care o declarație de trecere este absolut necesară (există „s o teoremă în acest sens), dar există cazuri în care poate fi cea mai puțin slabă soluție. Aceste cazuri variază de la limbă în limbă, în funcție de construcțiile de nivel superior pe care le acceptă limbajul.

În C, de exemplu, cred că există trei scenarii de bază în care un goto este adecvat.

  1. Ieșirea dintr-o buclă imbricată. Acest lucru nu ar fi necesar dacă limba ar avea o declarație de pauză etichetată.
  2. Salvarea dintr-o secțiune de cod (de obicei un corp funcțional) în caz de eroare sau alt eveniment neașteptat . Acest lucru nu ar fi necesar dacă limba ar avea excepții.
  3. Implementarea unei mașini de stări finite explicite. În acest caz (și, cred, numai în acest caz), un goto corespunde direct unui concept din domeniul problemei, trecând de la o stare la o altă stare specificată, unde starea curentă este reprezentată de blocul de cod care se execută în prezent .

Pe de altă parte, o mașină explicită cu stări finite poate fi de asemenea implementată cu o instrucțiune switch într-o buclă. Acest lucru are avantajul că fiecare stare începe în același loc din cod, ceea ce poate fi util pentru depanare, de exemplu.

Utilizarea principală a unui goto într-un limbaj rezonabil modern (unul care acceptă if / else și bucle) este de a simula o construcție de flux de control care lipsește din limbă.

Comentarii

  • Acesta este de fapt cel mai bun răspuns de până acum – destul de surprinzător, pentru o întrebare care are un an și jumătate. 🙂
  • +1 până la ” cel mai bun răspuns de până acum „. — ” Utilizarea principală a unui goto într-un limbaj relativ modern (unul care acceptă if / else și bucle) este de a simula un flux de control construiți că ‘ lipsesc din limbă. ”
  • În mașina de stare a declarației de comutare, fiecare scriere în valoarea de control este într-adevăr o goto. SSSM ‘ sunt deseori structuri bune de utilizat, deoarece văd parează starea SM din construcția de execuție, dar nu ‘ elimină cu adevărat ” gotos „.
  • ” Toate celelalte fiind egale, codul a cărui structură reflectă cea a domeniului problemei tinde să fie mai ușor de citit și de întreținut. ” Eu ‘ știu acest lucru de mult timp, dar nu aveam cuvintele pentru a-l comunica atât de precis într-un mod în care alte programatorii pot și vor înțelege de fapt. Vă mulțumim pentru acest lucru.
  • Teorema programului structurat ” ” mă amuză, deoarece are tendința de a demonstra clar subliniază că utilizarea instrucțiunilor de programare structurată pentru a emula un Goto este mult mai puțin lizibilă decât utilizarea unui Goto!

Răspuns

Sigur depinde de limbajul de programare. Motivul principal goto a fost controversat din cauza efectelor sale negative care apar atunci când compilatorul vă permite să îl utilizați prea liberal. Probleme pot apărea, de exemplu, dacă vă permite să utilizați goto în așa fel încât să puteți accesa acum o variabilă neinițializată, sau mai rău, pentru a trece la o altă metodă și a vă deranja cu apelul grămadă. Ar trebui să fie responsabilitatea compilatorului să interzică fluxul de control fără sens.

Java a încercat să „rezolve” această problemă interzicând în întregime goto. Cu toate acestea, Java vă permite să utilizați return într-un bloc finally și astfel să faceți o excepție să fie înghițită din greșeală.Aceeași problemă este încă acolo: compilatorul nu își face treaba. Eliminarea goto din limbă nu a fost remediată.

În C #, goto este la fel de sigur ca break, continue, try/catch/finally și return. Nu vă permite să utilizați variabile neinițializate, nu vă permite să săriți dintr-un bloc final etc. Compilatorul se va plânge. Acest lucru se datorează faptului că rezolvă problema real , care este așa cum am spus fluxul de control fără sens. goto nu anulează în mod magic analiza atribuirii definite și alte verificări rezonabile ale compilatorului.

Comentarii

  • Ideea ta este că C # ‘ s goto nu este rău? Dacă da, acesta este cazul pentru fiecare limbaj modern folosit în mod obișnuit cu o construcție goto, nu numai C # …

Răspunde

Da. Când buclele dvs. sunt cuibărite la mai multe niveluri, goto este singurul mod de a ieși elegant dintr-o buclă interioară. Cealaltă opțiune este să setați un steag și să ieșiți din fiecare buclă dacă acel steag îndeplinește o condiție. Acest lucru este foarte urât și destul de predispus la erori. În aceste cazuri, goto este pur și simplu mai bun.

Desigur, declarația Java etichetată break face la fel lucru, dar fără a vă permite să treceți la un punct arbitrar din cod, care rezolvă problema cu îngrijire fără a permite lucrurilor care fac goto rău.

Comentarii

  • Goto nu este niciodată un răspuns elegant. Când buclele dvs. sunt cuibărite la mai multe niveluri, problema dvs. este că nu ați reușit să vă arhitecturați codul pentru a evita buclele multinestate. inamicul. (Citiți ” Lambda: The Ultimate … ” hârtii.) Folosind un goto pentru a ieși din bucle imbricate mai multe nivele de adâncime pune o bandă de ajutor pe o fractură multiplă deschisă: poate fi simplu, dar nu este ‘ t răspunsul corect.
  • Și, desigur, acolo nu este niciodată cazul ciudat când sunt solicitate bucle adânc imbricate? A fi un bun programator nu este nu trebuie doar să respectați regulile, ci și să știți când să le încălcați.
  • @ JohnR.Strohm Nu spuneți niciodată. Dacă utilizați termeni precum ” niciodată ” în programare, ‘ în mod clar nu ați tratat cu carcase de colț, optimizare, contra-resurse etc. În buclele adânc imbricate, go este într-adevăr cel mai curat și elegant mod de a ieși din bucle. ‘ nu contează cât de mult ‘ ți-ai refactorizat codul.
  • @ JohnR.Strohm: Al doilea cel mai ratat caracteristică la trecerea de la VB.NET la C #: bucla Do. De ce? Pentru că pot schimba o buclă care are nevoie de o pauză profundă într-o buclă Do și tastați Exit Do și acolo ‘ s nu GoTo. Buclele imbricate se întâmplă tot timpul. Spargerea stivelor se întâmplă o parte din timp.
  • @ JohnR.Strohm Singurul motiv pentru care spuneți ” nu este niciodată un răspuns elegant ” se datorează faptului că v-ați gândit că goto nu este niciodată un răspuns elegant și, prin urmare, orice soluție care utilizează goto nu poate fi un răspuns elegant.

Răspuns

Cea mai mare parte a descurajării provine dintr-un fel de „religie” care a fost creată de Dumnezeu Djikstra, care a fost convingătoare la începutul anilor 60 despre puterea sa nediscriminată de a :

  • sări oriunde în orice bloc de cod
    • funcție neexecutată de la început
    • bucle neexecutate de la început
    • s-a ignorat inițializarea variabilă
  • sări de la orice bloc de cod fără nicio curățare posibilă.

Acest lucru nu are nimic de-a face cu goto declarație a limbilor moderne, a căror existență se datorează doar susținerii cr acțiunea altor structuri de cod decât cele furnizate de limbă.

În special, primul punct principal de mai sus este mai permis și al doilea este curățat (dacă goto din un bloc stiva este derulat corect și toți distructorii corespunzători sunt numiți)

Puteți consulta acest răspuns pentru a avea o idee despre modul în care codul egal nu este utilizarea goto poate fi ilizibilă. Problema nu este în sine, ci utilizarea defectuoasă a acestuia.

Pot scrie un întreg program fără să folosesc if, doar for. Desigur, nu va putea fi citit bine, un aspect stângaci și complicat inutil.

Dar problema nu este for. Sunt eu.

Lucruri precum break, continue, throw, bool needed=true; while(needed) {...}, etc. notează mai mult de masquerade goto pentru a scăpa de cimitirele fanaticilor djikstrarieni, că – La 50 de ani de la inventarea lacurilor moderne – încă își doresc prizonierii. Au uitat despre ce vorbea Djikstra, își amintesc doar titlul notei sale (GOTO a considerat dăunător și nici măcar nu era singurul său titlu: a fost schimbat de editor) și învinovățesc și bash, bash și blamează orice contruct care are acelea 4 scrisoare plasată în ordine.

Este 2011: este timpul să înțelegem că goto trebuie să se ocupe de GOTO declarație despre care Djikstra a fost convingătoare.

Comentarii

  • ” Lucruri precum pauza, continuați , arunca, bool nevoie = adevărat; în timp ce (este necesar) {…}, etc., notează mai mult decât mascarada, merg la ” Nu ‘ nu sunt de acord cu asta. Aș prefera ” lucruri precum break etc sunt restricționate merg ” sau ceva de genul acesta. Principala problemă cu Goto este că este de obicei prea puternică. În măsura în care actualul pas este mai puțin puternic decât Dijkstra ‘ s, răspunsul dvs. este în regulă cu mine.
  • @MuhammadAlkarouri: Sunt total de acord. Tocmai ați găsit o formulare mai bună pentru a-mi exprima exact conceptul. Ideea mea este că aceste restricții uneori nu pot fi aplicabile și tipul de restricție de care aveți nevoie nu este în limba respectivă. Apoi, un lucru mai ” mai puternic „, mai puțin specializat, este ceea ce te face capabil să rezolvi problema. De exemplu, Java break n nu este disponibil în C ++, deci goto escape, chiar dacă escape nu este necesar să fie doar ieșit din bucla n-ple.

Răspuns

Cea ciudată sau acolo, atâta timp cât este local pentru o funcție, rareori dăunează semnificativ lizibilității. De multe ori îl avantajează atrăgând atenția asupra faptului că se întâmplă ceva neobișnuit în acest cod care necesită utilizarea unei structuri de control oarecum neobișnuite .

Dacă erorile (locale) dăunează semnificativ lizibilității, atunci este de obicei un semn că funcția care conține goto a devenit prea complexă.

Ultimul goto pe care l-am pus într-un o bucată de cod C a fost să construiască o pereche de bucle de interblocare. Nu se încadrează în definiția normală a utilizării „acceptabile”, dar rezultatul a fost semnificativ mai mic și mai clar. Pentru a evita trecerea, ar fi fost nevoie de o încălcare a DRY-ului deosebit de dezordonată.

Comentarii

  • Răspunsul la acest lucru este cel mai blând declarat în vechiul ” Lay ‘ Chips de cartofi ” slogan: ” Pariu că poți ‘ să mănânci doar unul „. În exemplul dvs., aveți două ” interconectare ” (orice ar însemna asta și eu ‘ Pariez că nu este ‘ t destul) bucle, iar jocul ți-a dat o ieșire ieftină. Dar tipul de întreținere, care trebuie să modifice codul respectiv după ce ai fost lovit de un autobuz? Goto-ul îi va face viața mai ușoară sau mai grea? Aceste două bucle trebuie regândite?

Răspuns

Cred că toată această problemă a fost un caz de lătrat arborele greșit.

GOTO ca atare nu mi se pare problematic, ci mai degrabă este foarte des un simptom al unui păcat real: codul spaghetti.

Dacă GOTO cauzează trecerea majoră a liniilor de control al debitului, atunci este rău, punct. Dacă nu traversează nicio linie de control al debitului, este inofensiv. În zona cenușie dintre acestea avem lucruri precum salvarea buclelor, există încă câteva limbi care nu au adăugat structuri care acoperă toate cazurile gri legitime.

Singurul caz în care m-am găsit folosindu-l de fapt în mulți ani este cazul buclei în care punctul de decizie este în mijlocul buclei. Vă rămâne fie un cod duplicat, un steag sau un GOTO. Găsesc soluția GOTO cea mai bună dintre cele trei. Nu există încrucișare a liniilor de control al fluxului aici, este inofensiv.

Comentarii

  • Cazul la care faceți aluzie este uneori supranumit „buclă și jumătate” sau „N plus o jumătate de buclă” și este un caz de utilizare celebru pentru goto s care intră într-o buclă (dacă limba permite acest lucru; deoarece celălalt caz, sărind din buclă în mijloc, este de obicei banal fără goto ).
  • (Din păcate, majoritatea limbilor interzic sări în buclă.)
  • @KonradRudolph: Dacă implementați bucla ” ” cu GOTO nu există nicio altă structură de buclă în care sări.
  • Cred că goto ar striga FLUXUL DE CONTROL AICI ‘ NU SE ADAPTĂ LA PROGRAMARE STRUCTURATĂ NORMALĂ MODELE . Deoarece fluxurile de control care se potrivesc tiparelor de programare structurate sunt mai ușor de argumentat decât cele care nu ‘ t, ar trebui să încercăm să folosim astfel de modele atunci când este posibil; dacă codul se potrivește cu astfel de modele, nu ar trebui să ‘ să strigi că nu ‘ t. Pe de altă parte, în cazurile în care codul într-adevăr nu ‘ nu se potrivește cu astfel de modele, strigarea despre el poate fi mai bună decât pretenția că codul se potrivește atunci când nu într-adevăr ‘ t.
  • @supercat Ei bine, imaginează-ți că ți-ai scris un program și apoi vântul îți suflă din mâini. Conform logicii dvs., nu ar trebui ‘ să-l recuperați, deoarece urmărirea după programul dvs. nu a fost ‘ t în programul dvs.

Răspuns

Da, goto poate fi folosit pentru a beneficia de experiența dezvoltatorului: http://adamjonrichardson.com/2012/02/06/long-live-the-goto-statement/

Totuși, la fel ca în cazul oricărui instrument puternic (indicatori, moștenire multiplă etc.), trebuie să fie disciplinat folosindu-l. Exemplul furnizat în link folosește PHP, care restricționează utilizarea construcției goto la aceeași funcție / metodă și dezactivează posibilitatea de a intra într-un nou bloc de control (de exemplu, buclă, instrucțiune de schimbare etc.)

Răspuns

Depinde de limbă. De exemplu, este încă utilizat pe scară largă în programarea Cobol. Am lucrat și pe un dispozitiv Barionet 50, al cărui limbaj de programare firmware este un dialect BASIC timpuriu care, desigur, necesită utilizarea Goto.

Răspuns

goto poate fi util atunci când se transportă codul asamblator vechi la C. În prima instanță, o instrucțiune- conversia instrucțiunilor secundare în C, folosind goto ca înlocuitor al instrucțiunii asamblorului „s branch, poate permite portarea foarte rapidă.

Comentarii

  • Corect, dar unul dintre argumentele împotriva goto s este că împiedică optimizările compilatorului.
  • @Sapphire_Brick: Multe optimizări ale compilatorului sunt proiectate în jurul anumitor tipare de execuție. Dacă sarcina care trebuie efectuată nu se potrivește cu modelele de execuție acceptate, ” contracararea optimizărilor ” fii un lucru rău.

Răspuns

Aș argumenta că nu. Acestea ar trebui să fie întotdeauna înlocuite cu un instrument mai specific problemei pe care este folosit pentru a o rezolva (cu excepția cazului în care nu este disponibil în limba dvs.). gestionarea erorilor.

Comentarii

  • ‘ susțin că atunci când limbile au ambele aceste caracteristici, goto este de obicei absent din acele limbi.
  • Dar asta se datorează faptului că nu au ‘ Nu aveți nevoie de ele sau pentru că oamenii cred că nu ‘ nu au nevoie de ele?
  • Opiniile dvs. sunt fanatice. Există multe cazuri când goto este cel mai apropiat de semantica domeniului problematic, orice altceva ar fi un hack murdar.
  • @ SK-logic: Eu nu ‘ nu cred că cuvântul ” bigot ” înseamnă ceea ce crezi că înseamnă.
  • @Keith,

devotat intolerant propriilor sale opinii și prejudecăți ” – că ‘ este ceea ce am observați în mod constant aici, cu acest lot legat la ochi. ” Ar trebui întotdeauna înlocuit ” sunt fanatici ‘ s cuvinte, cel puțin. Nimic apropiat de o opinie corectă, sănătoasă, ci doar o pură fanatism. Acest ” întotdeauna ” nu lasă spațiu pentru nicio opinie alternativă, vezi?

Răspuns

Aș spune că nu. Dacă găsiți nevoia de a utiliza GOTO, pariez că trebuie să reproiectați codul.

Comentarii

  • Poate, dar tu ‘ nu a oferit niciun raționament
  • Dijkstra a oferit raționamentul, în detaliu, cu zeci de ani în urmă.
  • Doar Dogma. Fără rezonanțe. Notă: Djikstra NU MAI ESTE O REZONNĂ VALABILĂ: se referea la declarația BASIC sau FORTRAN GOTO din anii ‘ anii 60. Nu au nimic de-a face cu adevăratul anemic (în comparație cu puterea acelor) gots-s de astăzi.
  • @EmilioGaravaglia Ei bine, partea raționamentului său care se aplică și astăzi este că ‘ este foarte ușor să scrieți codul spaghete folosind drumul către mai mulți gotos. Cu toate acestea, după această logică, nu ar trebui să ‘ să folosim pointeri, deoarece utilizarea a atâtor pointeri cât number of gotos needed to create problems ar crea haos similar.

Lasă un răspuns

Adresa ta de email nu va fi publicată. Câmpurile obligatorii sunt marcate cu *