it-swarm.it

Vale la pena usare goto?

goto è quasi universalmente scoraggiato. Usare questa affermazione è mai utile?

30
Casebash

Questo è stato discusso più volte su StackTranslate.it e Chris Gillum ha riassunto i possibili usi di goto :

Uscita pulita da una funzione

Spesso in una funzione, è possibile allocare risorse e dover uscire in più punti. I programmatori possono semplificare il loro codice inserendo il codice di pulizia delle risorse alla fine della funzione, tutti i "punti di uscita" della funzione dovrebbero andare sull'etichetta di pulizia. In questo modo, non è necessario scrivere il codice di pulizia in ogni "punto di uscita" della funzione.

Uscita da loop nidificati

Se sei in un ciclo nidificato e hai bisogno di uscire da tutto cicli, un goto può renderlo molto più pulito e più semplice delle dichiarazioni di interruzione e degli if-check.

Miglioramenti delle prestazioni di basso livello

Questo è valido solo nel codice perf-critico, ma le istruzioni goto vengono eseguite molto rapidamente e possono darti una spinta quando ti muovi attraverso una funzione. Questa è un'arma a doppio taglio, perché un compilatore in genere non può ottimizzare il codice che contiene gotos.

Direi, come molti altri direbbero, che in tutti questi casi, l'uso di goto è usato come mezzo per uscire da un angolo in cui si è codificati, ed è generalmente un sintomo di codice che potrebbe essere refactored.

51
user8

I costrutti di flusso di controllo di livello superiore tendono a corrispondere ai concetti nel dominio del problema. Un if/else è una decisione basata su una condizione. Un loop dice di eseguire alcune azioni ripetutamente. Anche una dichiarazione di rottura dice "lo stavamo facendo ripetutamente, ma ora dobbiamo fermarci".

Un'istruzione goto, d'altra parte, tende a corrispondere a un concetto nel programma in esecuzione, non nel dominio del problema. Dice di continuare l'esecuzione in un punto specificato nel programma . Qualcuno che legge il codice deve dedurre cosa significa rispetto al dominio problematico.

Naturalmente tutti i costrutti di livello superiore possono essere definiti in termini di goto e semplici rami condizionali. Ciò non significa che siano semplicemente goto sotto mentite spoglie. Pensali come restrizioni goto - ed è le restrizioni che le rendono utili. Un'istruzione break è implementata come un salto alla fine del ciclo che la racchiude, ma è meglio pensarla come operante sul ciclo nel suo insieme.

A parità di tutto il resto, il codice la cui struttura riflette quella del dominio problematico tende a essere più facile da leggere e mantenere.

Non ci sono casi in cui un'istruzione goto è assolutamente richiesta (c'è n teorema in tal senso), ma ci sono casi in cui può essere la soluzione meno negativa. Tali casi variano da una lingua all'altra, a seconda di quali costrutti di livello superiore siano supportati dalla lingua.

In C, ad esempio, credo che ci siano tre scenari di base in cui un goto è appropriato.

  1. Uscire da un ciclo annidato. Ciò non sarebbe necessario se la lingua avesse un'istruzione break etichettata.
  2. Salvataggio da un tratto di codice (in genere un corpo di funzione) in caso di errore o altro evento imprevisto. Ciò non sarebbe necessario se la lingua avesse eccezioni.
  3. Implementazione di una macchina a stati finiti esplicita. In questo caso (e, penso, solo in questo caso) un goto corrisponde direttamente a un concetto nel dominio del problema, passando da uno stato a un altro stato specificato, in cui lo stato corrente è rappresentato da quale blocco di codice è attualmente in esecuzione .

D'altra parte, una macchina a stati finiti esplicita può anche essere implementata con un'istruzione switch all'interno di un ciclo. Ciò ha il vantaggio che ogni stato inizia nello stesso punto del codice, che può essere utile per il debug, ad esempio.

L'uso principale di un goto in un linguaggio ragionevolmente moderno (uno che supporta if/else e loop) è di simulare un costrutto del flusso di controllo che manca al linguaggio.

46
Keith Thompson

Sicuramente dipende dal linguaggio di programmazione. Il motivo principale per cui goto è stato controverso è a causa dei suoi effetti negativi che si verificano quando il compilatore ti consente di utilizzarlo in modo troppo libero. Ad esempio, possono sorgere problemi se ti consente di utilizzare goto in modo tale da poter ora accedere a una variabile non inizializzata, o peggio ancora, per saltare in un altro metodo e pasticciare con lo stack di chiamate. Dovrebbe essere responsabilità del compilatore impedire il flusso di controllo senza senso.

Java ha tentato di "risolvere" questo problema vietando del tutto goto. Tuttavia, Java consente di utilizzare return all'interno di un blocco finally e quindi causare un'ingiunzione involontaria di un'eccezione. Lo stesso problema è ancora presente: il compilatore è non sta facendo il suo lavoro. La rimozione di goto dalla lingua non l'ha risolto.

In C #, goto è sicuro come break, continue, try/catch/finally e return. Non ti consente di utilizzare variabili non inizializzate, non ti consente di saltare da un blocco finalmente, ecc. Il compilatore si lamenterà. Questo perché risolve il problema reale, che è come ho detto flusso di controllo senza senso. goto non annulla magicamente l'analisi di assegnazione definita e altri controlli del compilatore ragionevoli.

11
Timwi

Sì. Quando i tuoi loop sono nidificati a diversi livelli di profondità, goto è il modo solo di uscire elegantemente da un loop interno. L'altra opzione è quella di impostare una bandiera e uscire da ogni ciclo se quella bandiera soddisfa una condizione. Questo è davvero brutto e piuttosto soggetto a errori. In questi casi, goto è semplicemente migliore.

Naturalmente, l'istruzione break di Java fa la stessa cosa, ma senza permetterti di saltare a un punto arbitrario nel codice, il che risolve il problema ordinatamente senza consentire le cose che rendono goto malvagio.

9
Chinmay Kanchi

La maggior parte dello scoraggiamento deriva da una sorta di "religione" che è stata creata suscitando Dio Djikstra che era irresistibile nei primi anni '60 per il suo potere indiscriminato di:

  • saltare ovunque in qualunque blocco di codice
    • funzione non eseguita dall'inizio
    • loop non eseguiti dall'inizio
    • inizializzazione variabile saltata
  • saltare lontano da qualsiasi blocco di codice senza alcuna possibile pulizia.

Ciò non ha più nulla a che fare con l'istruzione goto dei linguaggi moderni, la cui esistenza è semplicemente dovuta al supporto della creazione di strutture di codice diverse da quelle fornite dal linguaggio.

In particolare, il primo punto principale sopra è più consentito e il secondo viene ripulito (se goto su un blocco lo stack viene svolto correttamente e tutti i distruttori appropriati vengono chiamati)

Puoi fare riferimento questa risposta per avere un'idea di come anche il codice che non usa goto possa essere illeggibile. Il problema non è quello di andare in se stesso, ma il suo cattivo utilizzo.

Posso scrivere un intero programma senza usare if, solo for. Certo, non sarà ben leggibile, un aspetto goffo e inutilmente complicato.

Ma il problema non è for. Sono io.

Cose come break, continue, throw, bool needed=true; while(needed) {...}, ecc. Stanno notando più di masquerade goto per fuggire dagli scimitarre degli zeloti Djikstrariani, che -50 anni dopo l'invenzione dei moderni laguages- vogliono ancora i loro prigionieri. Hanno dimenticato di cosa stava parlando Djikstra, ricordano solo il titolo della sua nota (GOTO considerato dannoso, e non era nemmeno il suo titolo onw: era stato modificato dall'editore) e la colpa e la bash, la bash e la colpa di ogni contratto avevano quelle 4 lettera posta in sequenza.

È il 2011: è tempo di capire che goto non ha intenzione di occuparsi dell'affermazione GOTO di cui Djikstra era avvincente.

7

Lo strano goto qui o là, purché sia ​​locale a una funzione, raramente danneggia significativamente la leggibilità. Spesso ne beneficia attirando l'attenzione sul fatto che in questo codice sta succedendo qualcosa di insolito che richiede l'uso di una struttura di controllo piuttosto rara.

Se i goto (locali) danneggiano in modo significativo la leggibilità, di solito è un segno che la funzione contenente il goto è diventata troppo complessa.

L'ultima goto che ho inserito in un pezzo di codice C è stata quella di costruire una coppia di anelli ad incastro. Non rientra nella normale definizione di utilizzo "accettabile", ma la funzione è risultata significativamente più piccola e più chiara di conseguenza. Per evitare il goto avrebbe richiesto una violazione particolarmente disordinata di DRY.

4
blucz

Penso che l'intero problema sia stato il caso di abbaiare l'albero sbagliato.

GOTO in quanto tale non mi sembra problematico, ma piuttosto è molto spesso un sintomo di un vero peccato: il codice spaghetti.

Se il GOTO causa l'attraversamento importante delle linee di controllo del flusso, allora è un punto sbagliato. Se non attraversa le linee di controllo del flusso è innocuo. Nella zona grigia in mezzo abbiamo cose come i salvataggi del ciclo, ci sono ancora alcune lingue che non hanno aggiunto costrutti che coprono tutti i casi grigi legittimi.

L'unico caso in cui mi sono ritrovato a usarlo effettivamente in molti anni è il caso del ciclo in cui il punto decisionale si trova nel mezzo del ciclo. Ti rimane un codice duplicato, una bandiera o un GOTO. Trovo la soluzione GOTO la migliore delle tre. Non vi è alcun incrocio di linee di controllo del flusso qui, è innocuo.

3
Loren Pechtel

Sì, il goto può essere utilizzato a beneficio dell'esperienza dello sviluppatore: http://adamjonrichardson.com/2012/02/06/long-live-the-goto-statement/

Tuttavia, proprio come con qualsiasi strumento potente (puntatori, ereditarietà multipla, ecc.), Bisogna essere disciplinati usandolo. L'esempio fornito nel collegamento utilizza PHP, che limita l'utilizzo del costrutto goto alla stessa funzione/metodo e disabilita la possibilità di saltare in un nuovo blocco di controllo (ad es. Loop, istruzione switch, ecc.)

1
AdamJonR

Dipende dalla lingua. È ancora ampiamente usato nella programmazione Cobol, per esempio. Ho anche lavorato su un dispositivo Barionet 50, il cui linguaggio di programmazione del firmware è un dialetto BASIC iniziale che ovviamente richiede l'uso di Goto.

1
user16764

Direi di no. Se trovi la necessità di utilizzare GOTO, scommetto che è necessario riprogettare il codice.

0
Walter

goto può essere utile quando si esegue il porting del codice dell'assemblatore legacy su C. Nella prima istanza, una conversione istruzione per istruzione in C, usando goto come sostituto dell'assembly branch istruzione, può abilitare il porting molto rapido.

0
Graham Borland