L'utilizzo di goto è sempre utile?

27

goto è quasi universalmente scoraggiato. Utilizzare questa affermazione è sempre utile?

    
posta Casebash 02.09.2010 - 23:49
fonte

12 risposte

48

Questo argomento è stato discusso più volte su Stack Overflow e Chris Gillum ha riepilogato i possibili usi di goto :

Cleanly exiting a function

Often in a function, you may allocate resources and need to exit in multiple places. Programmers can simplify their code by putting the resource cleanup code at the end of the function all all "exit points" of the function would goto the cleanup label. This way, you don't have to write cleanup code at every "exit point" of the function.

Exiting nested loops

If you're in a nested loop and need to break out of all loops, a goto can make this much cleaner and simpler than break statements and if-checks.

Low-level performance improvements

This is only valid in perf-critical code, but goto statements execute very quickly and can give you a boost when moving through a function. This is a double-edged sword, however, because a compiler typically cannot optimize code that contains gotos.

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

    
risposta data 02.09.2010 - 23:59
fonte
40

I costrutti del flusso di controllo di livello superiore tendono a corrispondere ai concetti nel dominio del problema. An if / else è una decisione basata su alcune condizioni. Un loop dice di eseguire più volte un'azione. Anche una frase di separazione 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 inferire che cosa significhi rispetto al dominio del problema.

Naturalmente tutti i costrutti di livello superiore possono essere definiti in termini di gotos e rami condizionali semplici. Ciò non significa che siano semplicemente goto sotto mentite spoglie. Pensa a loro come restricted gotos - e sono le restrizioni che li rendono utili. Un'istruzione break è implementata come un salto alla fine del ciclo di chiusura, ma è meglio pensarla come operativa sul loop nel suo complesso.

A parità di tutti gli altri, il codice la cui struttura riflette quella del dominio del problema tende a essere più facile da leggere e mantenere.

Non ci sono casi in cui una dichiarazione goto è assolutamente necessaria (c'è un teorema in questo senso), ma ci sono casi in cui può essere la soluzione meno cattiva. Questi casi variano da lingua a lingua, a seconda dei costrutti di livello superiore supportati dalla lingua.

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

  1. Rottura da un loop annidato. Ciò non sarebbe necessario se la lingua avesse un'istruzione break etichettata.
  2. Uscendo da un tratto di codice (in genere un corpo di una 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 espliciti. 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 espliciti può anche essere implementata con un'istruzione switch all'interno di un loop. Questo ha il vantaggio che ogni stato inizia nello stesso punto nel 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 di flusso di controllo che manca nella lingua.

    
risposta data 06.02.2012 - 10:51
fonte
11

Sicuramente dipende dal linguaggio di programmazione. Il motivo principale per cui goto è stato controverso è a causa dei suoi effetti negativi che sorgono quando il compilatore ti permette di usarlo troppo liberamente. Ad esempio, possono sorgere problemi se ti consente di utilizzare goto in modo tale che ora puoi accedere a una variabile non inizializzata o, peggio, a saltare in un altro metodo e ad interferire con lo stack di chiamate. Dovrebbe essere la responsabilità del compilatore di non consentire un flusso di controllo assurdo.

Java ha tentato di "risolvere" questo problema disabilitando completamente goto . Tuttavia, Java ti consente di usare return all'interno di un blocco finally e quindi causare un'eccezione di ingerenza accidentale. Lo stesso problema è ancora lì: il compilatore non sta facendo il suo lavoro. La rimozione di goto dalla lingua non l'ha corretto.

In C #, goto è sicuro come break , continue , try/catch/finally e return . Non ti permette di usare variabili non inizializzate, non ti lascia saltare da un blocco finale, ecc. Il compilatore si lamenterà. Questo perché risolve il problema reale , che è come ho detto un flusso di controllo assurdo. goto non cancella magicamente l'analisi delle assegnazioni definite e altri controlli del compilatore ragionevoli.

    
risposta data 07.09.2010 - 00:14
fonte
8

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

Ovviamente, l'istruzione break etichettata da Java fa la stessa cosa, ma senza consentire di passare a un punto arbitrario nel codice, che risolve il problema ordinatamente senza consentire le cose che rendono goto male.

    
risposta data 02.09.2010 - 23:58
fonte
7

La maggior parte dello scoraggiamento arriva da una sorta di "religione" creata intorno a Dio Djikstra che era avvincente nei primi anni '60 del suo potere indiscriminato di:

  • salta ovunque in qualunque blocco di codice
    • funzione non eseguita dall'inizio
    • cicli non eseguiti dall'inizio
    • inizializzazione della variabile ignorata
  • salta fuori da qualunque blocco di codice senza alcuna possibile pulizia.

Questo non ha più nulla a che fare con la dichiarazione goto delle lingue moderne, la cui esistenza è semplicemente dovuta a supportare la creazione di strutture di codice diverse da quelle fornite dalla lingua.

In particolare il primo punto principale sopra è più permesso e il secondo è pulito (se tu goto su un blocco lo stack è srindicato correttamente e tutti i distruttori corretti hanno chiamato)

Puoi fare riferimento a questa risposta per avere un'idea di come anche il codice che non utilizza goto possa essere illeggibile. Il problema non è goto stesso, ma il cattivo uso di esso.

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. notano più di masquerade goto per sfuggire alle scimitarre degli zeloti di Djikstrarian, che -50 anni dopo l'invenzione dei moderni laguages- vogliono ancora i loro prigionieri. Hanno dimenticato ciò di cui parlava Djikstra, ricordano solo il titolo del suo biglietto (GOTO considera dannoso, e non era nemmeno il suo titolo onw: è stato modificato dall'editore) e incolpano e colpiscono, bash e incolpano ogni controt avendo quelli 4 lettera inserita in sequenza.

È il 2011: è giunto il momento di capire che goto ha deciso di occuparsi dell'istruzione GOTO di cui Djikstra era avvincente.

    
risposta data 06.02.2012 - 10:18
fonte
4

Il goto dispari qui o là, a patto che sia locale a una funzione, raramente nuoce significativamente alla leggibilità. Spesso ne trae beneficio richiamando l'attenzione sul fatto che c'è qualcosa di insolito in questo codice che richiede l'uso di una struttura di controllo piuttosto rara.

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

L'ultimo goto che ho inserito in un pezzo di codice C è stato quello di costruire un paio di loop ad incastro. Non si adatta alla normale definizione di "goto" accettabile, ma la funzione è risultata significativamente più piccola e chiara come risultato. Per evitare il goto avrebbe richiesto una violazione particolarmente disordinata di DRY.

    
risposta data 03.09.2010 - 01:52
fonte
2

Penso che l'intera questione sia stata un caso di abbaiare dall'albero sbagliato.

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

Se GOTO causa un grande incrocio di linee di controllo del flusso, allora è un periodo negativo. Se non attraversa linee di controllo del flusso è innocuo. Nella zona grigia in mezzo abbiamo cose come i salvataggi di loop, ci sono ancora alcune lingue che non hanno aggiunto costrutti che coprono tutti i casi grigi legittimi.

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

    
risposta data 06.02.2012 - 17:32
fonte
1

Sì, il goto può essere utilizzato per avvantaggiare l'esperienza dello sviluppatore: link

Tuttavia, proprio come con qualsiasi strumento potente (puntatori, eredità multipla, ecc.), si deve essere disciplinati usandolo. L'esempio fornito nel collegamento utilizza PHP, che limita l'uso del costrutto goto alla stessa funzione / metodo e disabilita la possibilità di passare a un nuovo blocco di controllo (ad esempio, istruzione loop, switch, ecc.)

    
risposta data 06.02.2012 - 09:14
fonte
1

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 è uno dei primi dialetti BASIC che ovviamente richiede l'utilizzo di Goto.

    
risposta data 06.02.2012 - 15:54
fonte
0

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

    
risposta data 03.09.2010 - 00:42
fonte
0

goto può essere utile quando si porta il codice assembler legacy a C. Nella prima istanza, una conversione istruzione-per-istruzioni in C, usando goto come sostituzione per l'istruzione branch dell'assemblatore, può abilitare molto porting rapido.

    
risposta data 06.02.2012 - 12:55
fonte
-1

Direi di no. Dovrebbero essere sempre sostituiti con uno strumento più specifico del problema che il goto viene utilizzato per risolvere (a meno che non sia disponibile nella tua lingua). Ad esempio, le istruzioni di interruzione e le eccezioni risolvono i problemi precedentemente risolti da goto dell'escaping di loop e della gestione degli errori.

    
risposta data 03.09.2010 - 00:40
fonte

Leggi altre domande sui tag