In un articolo recente , Andrew Koenig scrive:
When asked why
goto
statements are harmful, most programmers will say something like "because they make programs hard to understand." Press harder, and you may well hear something like "I don't really know, but that's what I was taught." For that reason, I'd like to summarize Dijkstra's arguments.
Quindi mostra due frammenti di programma, uno senza goto
e uno con goto
:
if (n < 0)
n = 0;
Assuming that n is a variable of a built-in numeric type, we know that after this code, n is nonnegative.
Suppose we rewrite this fragment:
if (n >= 0) goto nonneg;
n = 0;
nonneg: ;
In theory, this rewrite should have the same effect as the original. However, rewriting has changed something important: It has opened the possibility of transferring control to nonneg from anywhere else in the program.
Ho sottolineato la parte con cui non sono d'accordo. I linguaggi moderni come C ++ fanno non consentono a goto
di trasferire il controllo arbitrariamente. Ecco due esempi:
- Non puoi saltare a un'etichetta definita in una funzione diversa.
- Non puoi saltare l'inizializzazione della variabile.
Ora considera di comporre il tuo codice di minuscole funzioni che aderiscono al principio di responsabilità singola:
int clamp_to_zero(int n)
{
if (n >= 0) goto n_is_not_negative:
n = 0;
n_is_not_negative:
return n;
}
L'argomento classico contro l'istruzione goto
è che il controllo potrebbe essere trasferito da ovunque all'interno del tuo programma all'etichetta n_is_not_negative
, ma questo semplicemente non è (e non è mai stato) vero in C ++ . Se lo provi, riceverai un errore del compilatore, perché le etichette hanno un ambito. Il resto del programma non vede nemmeno il nome n_is_not_negative
, quindi non è possibile saltare lì. Questa è una garanzia statica!
Ora, non sto dicendo che questa versione sia migliore allora quella senza goto
, ma per rendere quest'ultima espressiva come la prima, dovremmo almeno inserire un commento, o ancora meglio, un'affermazione:
int clamp_to_zero(int n)
{
if (n < 0)
n = 0;
// n is not negative at this point
assert(n >= 0);
return n;
}
Nota che in pratica ottieni l'asserzione gratuita nella versione goto
, perché la condizione n >= 0
è già scritta nella riga 1 e n = 0;
soddisfa banalmente la condizione. Ma questa è solo un'osservazione casuale.
Mi sembra che "non usare goto
s!" è uno di quei dogmi come "non usare più return
s!" che derivano da un momento in cui il problema reale erano funzioni di centinaia o anche migliaia di righe di codice.
Quindi, abbiamo ancora un caso contro l'istruzione goto, a parte il fatto che non è particolarmente utile? Non ho scritto un goto
in almeno un decennio, ma non è che stavo scappando terrorizzato ogni volta che ne ho incontrato uno. 1 Idealmente, mi piacerebbe vedere un argomento strong e valido contro goto
s che ancora regge quando si aderiscono ai principi di programmazione stabiliti per il codice pulito come l'SRP. "Puoi saltare ovunque" non è (e non è mai stato) un argomento valido in C ++, e in qualche modo non mi piace insegnare cose che non sono vere.
1: Inoltre, non sono mai stato in grado di resuscitare nemmeno un singolo velociraptor , indipendentemente da quanti goto
Ho provato: (