Completo la mia:Originariamente inviato da LeleFT
Posso chiederti il perchè del punto 3? O meglio:
[cite]
Citazione:
Originariamente inviato da MacApp
"Definisci le variabili solo un attimo prima di utilizzarle"
[/cite]
Se ci si riferisce a singole istruzioni come il for, n cui la variabile serve solo come contatore e non più usata in futuro, lo capisco e concordo,
ma le altre è preferibile dichiararle subito all'inizio: almeno c'è un solo posto dove andare a cercarle in caso di problemi, senza diventare matti a scorrere tutto il codice.
"Definisci le variabili solo un attimo prima di utilizzarle, e distruggile non appena hai finito d'utilizzarle"
equivalente a:
"Limitare il più possibile l'esistenza di variabili".
La cosa è talmente utile che spesso in C (dove invece è obbligatorio definirle all'inizio di un blocco di graffe), metto dei blocchi extra di graffe proprio per limitare l'esistenza di una variabile.
Per le seguenti ragioni:
1. Semantica;
2. Portabilità/Manuntenzione;
3. Modularizzazione;
4. Efficienza.
1. Semantica:
Proprio per evitare di dover scorrere il codice per capire dove sia definita e successivamente modificata una variabile. Similmente per le stesse ragioni per cui è meglio limitare (anzi escludere) l'utilizzo delle variabili globali.
2. Portabilità/Mantenibilità:
Portando il codice da un sistema operativo all'altro, da un compilatore all'altro, da una versione dello stesso programma all'altro, se ad esempio devi cambiare il tipo di una variabile nella chiamata di una funzione, le modifiche sono localizzate solo nell'intorno del codice di dove avviene appunto la chiamata alla funzione modificata.
3. Modularizzazione:
Mi accorgo che ciò che sto scrivendo può essere trasformato in una funzione, magari riutilizzabile altrove? Taglio il codice che sto scrivendo, lo funzionalizzo, senza inficiare il resto del programma.
4. Efficienza:
Ad esempio confronta le due funzioni:
Sbagliando si potrebbe pensare che TestVariabileAdInizioBlocco sia più efficiente di TestVariabileLimitata, perché la variabile locale viene definita una volta sola, mentre in TestVariabileLimitata viene definita N volte.Codice PHP:void TestVariabileAdInizioBlocco (){
QualunqueTipo a;
for (int i = 0; i < N; ++i){
a = GetObject (i); // Funzione che in base ad i restituisce un oggetto di tipo QualunqueTipo;
a.DumpObject (); // Metodo della classe QualunqueTipo che stampa su file di log se stessa.
HandleObject (a); // Funzione che fa qualcosa con l'oggetto di tipo a.
}
}
void TestVariabileLimitata (){
for (int i = 0; i < N; ++i){
QualunqueTipo a = GetObject (i); // Funzione che in base ad i restituisce un oggetto di tipo QualunqueTipo;
a.DumpObject (); // Metodo della classe QualunqueTipo che stampa su file di log se stessa.
HandleObject (a); // Funzione che fa qualcosa con l'oggetto di tipo a.
}
}
Ma.. in TestVariabileAdInizioBlocco, quando si assegna a "a = GetObject (i)" cosa accade? Viene chiamato l'operatore = della classe QualunqueTipo, che normalmente ha un codice equivalente (non condiviso) ad il suo distruttore + il costruttore di copia.
Quindi per la classe QualunqueTipo siamo obbligati a definire il costruttore senza argomenti, il costruttore di copia, l'operatore = che contiene codice equivalente (ma non condiviso) al distruttore ed al costruttore di copia, il distruttore.
In totale quindi in TestVariabileAdInizioBlocco vengono chiamati: Una volta il costruttore senza argomenti, N volte l'operatore = che equivale ad N chiamate del distruttore ed N chiamate del costruttore di copia, e finalmente una sola volta il distruttore.
Osserva che l'operatore = non potendo condividere lo stesso codice del costruttore di copia e del suo distruttore, deve essere mantenuto separatamente. Quindi se modifico il costruttore di copia, devo modificare anche l'operatore = ecc..
Invece in TestVariabileLimitata, non ho la necessità di definire il costruttore senza argomenti e neppure l'operatore = per la classe QualunqueTipo, viene chiamato N volte il costruttore di copia, ed N volte il suo distruttore.
Riepilogando nel primo caso devo per la classe QualunqueTipo:
- definire il costruttore senza argomenti;
- definire l'operatore = che ha codice equivalente (non condiviso) al codice del suo distruttore + il suo costruttore di copia;
- definire il costruttore di copia;
- definire il distruttore;
Nel secondo invece basta:
- definire il costruttore di copia;
- definire il distruttore;
Aggiungiamoci anche che nel secondo caso se (com'è probabile che sia) il metodo DumpObject è costante, ed HandleObject vuole solo un const QualunqueTipo, possiamo scrivere anche "const QualunqueTipo a = GetObject (i);"
Non solo... il corpo del for voglio trasformarlo in una funzione? Nel primo caso devo anche cancellare la definizione ad inizio blocco (e magari mi dimentico di farlo).
Insomma devo scrivere meno codice, riduco possibili errori di sincronia tra funzioni, ed in più il risultato è più efficiente.
Meglio di così?
;-)
"

Rispondi quotando