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. Pensa a loro come goto limitate - 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 necessaria (c'è un 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.
- Uscire da un ciclo annidato. Ciò non sarebbe necessario se la lingua avesse un'istruzione break etichettata.
- 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.
- 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.