Devo riutilizzare le variabili?


59

Devo riutilizzare le variabili?

So che molte best practice dicono che non dovresti farlo, tuttavia, in seguito, quando un altro sviluppatore sta eseguendo il debug del codice e hanno 3 variabili simili e l'unica differenza è che vengono create in diversi punti del codice, potrebbe essere confuso. Il test unitario ne è un ottimo esempio.

Comunque, io non so che migliori pratiche sono il più delle volte contro di essa. Ad esempio, dicono di non "sovrascrivere" i parametri del metodo.

Le migliori pratiche sono persino contro l'annullamento delle variabili precedenti (in Java c'è Sonar che avvisa quando si assegna nulla variabile, che non è necessario farlo per chiamare il garbage collector da Java 6. Non è sempre possibile controllare quali avvisi sono disattivati; il più delle volte l'impostazione predefinita è attiva.)


11
Da Java 6? Non è mai stato necessario assegnare null alle variabili in qualsiasi versione di Java. Quando una variabile esce dall'ambito, rilascia il riferimento al suo oggetto.
Kevin Panko,

35
il riutilizzo delle variabili è una delle prime cose che usano gli offuscatori di codice
Lelouch Lamperouge,

7
Il riutilizzo delle variabili è in conflitto con la scelta di identificatori decenti per le variabili. Nelle lingue moderne non ci sono davvero vantaggi nel riutilizzo variabile che supera i vantaggi di avere buoni identificatori.
Joren,

4
Si noti inoltre che non tutto il riutilizzo è riutilizzo. I vecchi programmatori FORTRAN, anche quelli che si sono trasferiti in altre lingue, usano abitualmente I, J, K, L, M, N (o i, j, k, l, m, n) per tutto il nostro DO-loop (for- loop) contatori. Siamo abituati a vedere cose come SOMMA = SOMMA + A (I, K) * B (K, J) o somma + = a [i] [k] * b [k] [j] ;.
John R. Strohm,

1
Il riutilizzo delle variabili potrebbe essere giustificato quando si programmano microcontrollori con risorse molto limitate (pochi kByte di RAM).
m.,

Risposte:


130

Il problema si presenta solo quando i metodi sono lunghi e eseguono più attività in sequenza. Ciò rende il codice più difficile da comprendere (e quindi mantenere) di per sé. Il riutilizzo delle variabili aggiunge un ulteriore elemento di rischio, rendendo il codice ancora più difficile da seguire e più soggetto a errori.

La migliore pratica dell'IMO consiste nell'utilizzare metodi abbastanza brevi che fanno solo una cosa, eliminando l'intero problema.


che dire di unit test? ad esempio devo verificare se dopo aver eseguito il metodo per la seconda volta funziona ancora come previsto.
IAdapter,

20
@IAdapter, il codice unit test è un problema diverso, in cui gli standard potrebbero essere più rilassati rispetto al codice di produzione. Tuttavia, renderlo leggibile e facile da mantenere è una priorità assoluta. Puoi (e dovresti) estrarre metodi dai tuoi test unitari, per renderli brevi e facili da leggere (ed eliminare la necessità di riutilizzare le variabili).
Péter Török,

3
@IAdapter, per lo scenario che hai descritto non riutilizzerei una variabile. La cosa appropriata sarebbe qualcosa di simile al fatto result1 = foo(); result2 = foo(); Assert.AreEqual(result1, result2);che non vedo molti posti in cui in questo caso avresti bisogno di riutilizzare una variabile.
JSB ձոգչ

1
@IAdapter per (int i = 0; i <2; i ++) {result = foo (); assertEquals (expectedResult, result);}
Bill K,

2
+1: questo è un buon odore di codice per quando fare metodi più piccoli.

49

Il riutilizzo delle variabili in un metodo è un segnale forte che dovresti rifattorizzare / dividerlo.

Quindi la mia risposta sarebbe che non dovresti riutilizzarli, perché se lo fai, sarebbe molto più difficile riformattarlo in seguito.


19

Dipende.

Alcune variabili potrebbero essere create esattamente allo scopo di contenere un determinato tipo di dati, che possono cambiare durante l'esecuzione di una funzione. I codici di ritorno vengono in mente qui, ad esempio:

void my_function() {
    HRESULT errorcode;
    errorcode = ::SomeWindowsApiFunction();
    if (FAILED(errorcode)) { /* handle error */ }
    errorcode = ::AnotherWindowsApiFunction();
    if (FAILED(errorcode)) { /* handle error */ }
}

Il nome della variabile rende molto chiaro ciò che questa variabile è destinata a memorizzare. Penso che siano possibili altri casi d'uso come questo, in cui una variabile è concettualmente un contenitore che viene logicamente utilizzato da diversi casi di cose molto simili nel corso di una funzione.

In generale, tuttavia, ciò dovrebbe essere fatto solo in circostanze in cui è assolutamente chiaro ai possibili lettori del codice. In nessun caso, tranne forse l'ottimizzazione estrema, indipendentemente dalla leggibilità del codice, una variabile dovrebbe essere riutilizzata solo perché il tipo si adatta.

Tutto ciò deriva fondamentalmente dalle buone pratiche nella denominazione variabile. I nomi dovrebbero parlare da soli. Se è difficile mettere lo scopo esatto per tutti i riutilizzi in un nome breve, è meglio usare solo variabili distinte.


15

Il motivo principale per cui non riutilizzo le variabili (specialmente nei test unitari) è perché introduce un percorso di codice non necessario, difficile da testare ed eseguire il debug. Un buon test unitario dovrebbe essere indipendente da altri test e quando riutilizzi la variabile di livello di classe (istanza) in un dispositivo di test unitario, devi assicurarti di far valere il loro stato prima di ogni test. Un buon test unitario isola anche i difetti, quindi in teoria ogni caso di test (metodo) dovrebbe affermare solo 1 comportamento per il sistema in prova. Se i metodi di test sono scritti in questo modo, raramente è necessario o utile riutilizzare una variabile a livello di metodo. Infine, nei linguaggi che supportano le chiusure e l'elaborazione asincrona, è davvero difficile ragionare su cosa diavolo sta succedendo se si riutilizzano le variabili in un metodo.


quindi dovrei scrivere metodi di test come -testSomething e affermare per l'invocazione a metodo singolo -testSomethingTwoInvocazioni e asserzioni per la sola seconda invocazione?
IAdapter,

2
Sì. Ti aiuta a individuare se è la prima o la seconda iterazione che non è riuscita. mspec può essere d'aiuto per questo, il suo albero di eredità sarà molto utile.
Bryan Boettcher,

Se usi "variabile" quando intendi "variabile di classe" o "variabile di istanza", devi esprimerti in modo più chiaro.
gnasher729,

13

Dovresti usare diverse variabili. Se sei preoccupato che il tuo collega sia confuso, dai loro nomi che coprano chiaramente i loro ruoli.
Il riutilizzo delle variabili è una probabile fonte di confusione in futuro; meglio chiarirlo ora.
In alcuni casi, è possibile riutilizzare lo stesso nome di variabile; ad esempio iin un semplice ciclo di conteggio. In questi casi, dovresti ovviamente assicurarti che le variabili siano nel loro ambito.

EDIT: il riutilizzo delle variabili è talvolta un segnale della violazione del principio di responsabilità singola . Verifica se la variabile riutilizzata viene utilizzata nello stesso ruolo. In tal caso, potrebbe non essere affatto riutilizzabile (sebbene possa essere preferibile avere due variabili diverse, per limitare l'ambito di tali variabili). Se viene utilizzato in ruoli diversi, hai una violazione SRP nelle tue mani.


4

C'è una situazione in cui potresti voler riutilizzare una variabile indipendentemente dal grande consiglio dato da altre risposte: quando il tuo compilatore ha bisogno di una mano.

In alcuni casi il compilatore potrebbe non essere abbastanza intelligente da rendersi conto che una determinata variabile allocata dal registro non viene più utilizzata dalla parte successiva del codice. Pertanto non riutilizzerà quel registro teoricamente libero per le variabili successive e il codice generato potrebbe non essere ottimale.

Nota che non conosco nessun compilatore tradizionale corrente che non riesca a cogliere correttamente questa situazione, quindi mai, mai, mai farlo a meno che tu non sappia per certo che il tuo compilatore sta generando un codice non ottimale. Se stai compilando per sistemi embedded speciali con compilatori personalizzati, potresti riscontrare ancora questo problema.


17
-1 a meno che non sia possibile indicare una situazione del mondo reale in cui ciò accade effettivamente e in cui il riutilizzo di una variabile fa una differenza apprezzabile. Questa è una soluzione teorica a un problema teorico e non molto valida. Laddove il compilatore decide di inserire variabili è la preoccupazione del compilatore; se il tuo compilatore genera codice scadente e se fa davvero la differenza, correggi o sostituisci il compilatore.
Caleb,

3
@Caleb: non hai sempre accesso al codice sorgente del compilatore per la piattaforma su cui stai sviluppando, in particolare per piattaforme embedded proprietarie. Ho anche HO dico nella mia risposta che io non so di nessun compilatori tradizionale corrente (o interpreti / VM appunto) che non svolgono correttamente questa analisi vitalità in tutti i casi che ho guardato. Tuttavia, ho già lavorato su sistemi embedded proprietari con i compilatori personalizzati che erano molto bare-bones in passato (10 anni fa o giù di lì). Il sistema aveva una capacità molto limitata, così come il compilatore, quindi questa situazione si è verificata lì.
Joris Timmermans,

2
+1 Ho fatto esattamente un tale riutilizzo nel progetto passato (codice media altamente ottimizzato scritto in ANSI C). Per quanto ricordo, la differenza era facilmente visibile nell'assemblaggio e misurabile nei parametri di riferimento. Mai e poi mai sperato che non sarà mai necessario fare un simile riutilizzo in Java.
moscerino

@Caleb correggere o sostituire il compilatore potrebbe non essere un'opzione per una serie di ragioni e devi semplicemente accontentarti di ciò che hai.

@ ThorbjørnRavnAndersen È concepibile che si possa essere costretti a usare un compilatore scadente, e inoltre che le prestazioni potrebbero essere così critiche che è necessario indovinare il compilatore e manipolare il codice per riutilizzare un registro? Sì. È probabile ? No. MadKeithV concorda sul fatto che non può fornire un esempio reale. È una buona pratica ? È di buon stile ? È un indicatore della qualità del codice ? Sicuramente no. È una risposta utile alla domanda scritta? Dovuto rispetto a MadKeithV, ma non credo che lo sia.
Caleb,

2

Direi NO.

Pensa a questo scenario: il tuo programma è andato in crash e devi capire cosa è successo controllando un dump del core ... riesci a vedere la differenza? ;-)


Se il core dump proviene da una build ottimizzata, è possibile che le variabili condividano comunque la memoria. Quindi è meno utile di quanto potrebbe essere.
Winston Ewert,

ovviamente, una build ottimizzata non è molto utile per il debug! ma in ogni caso hai ancora la possibilità di usare una build di debug ... E quando hai il debugger collegato, non devi andare passo passo dall'inizio di una funzione per vedere come cambiano le variabili, perché non lo fanno! MrGreen
fortran il

2

No, non stai migliorando il codice in esecuzione sulla macchina (... il codice assembly). Lascia riutilizzare la memoria utilizzata dal compilatore per la variabile. Molto spesso sarà un registro e il riutilizzo non ti ha comprato nulla. Concentrati sul rendere il codice più facile da leggere.


0

Dipende. In un linguaggio dinamico, in cui il tipo risiede su valori piuttosto che su variabili, se avessi un argomento ben definito per una funzione che, ad esempio, era una stringa. I un cambiamento nell'algoritmo significava che veniva sempre usato dopo essere stato interpretato come un numero intero, quindi, come prima bozza, potrei fare l'equivalente di

scrote = int (scrote)

Ma alla fine cercherò di cambiare il tipo inviato alla funzione e di notare il cambiamento nel tipo di parametro.


1
Mettere una riga come "scrote = int (scrote)" nel mezzo di un lungo batch di codice è un ottimo modo per far impazzire i programmatori di manutenzione.
jhocking

È più probabile che il problema riguardi il "lungo batch di codice" di cui parli.
Paddy3118,

Oltre alle note di risposta accettate, il riutilizzo delle variabili è davvero solo un problema con lunghi lotti di codice. Fondamentalmente, in qualsiasi situazione in cui dovresti scrivere qualcosa come "scrote = int (scrote)", preferirei mettere int (scrote) in una nuova variabile, o meglio passare int (scrote) a una nuova funzione.
scherzando il

0

Innanzitutto, guarda il tuo ambiente di sviluppo. Se hai problemi con il debug perché hai cinque variabili in ambiti diversi con nomi identici e il debugger non ti mostra quale di queste variabili è quella di cui hai bisogno, quindi non utilizzare cinque variabili con lo stesso nome. Ci sono due modi per raggiungere questo obiettivo: utilizzare una variabile o utilizzare cinque nomi diversi.

Il debugger può anche rendere doloroso eseguire il debug di una funzione con molte variabili. Se una funzione con 20 variabili è più difficile da eseguire il debug di una con 16 variabili, allora potresti prendere in considerazione la sostituzione di 5 variabili con una. ("Potrebbe considerare" non è lo stesso di "dovrebbe sempre").

Va bene avere una variabile utilizzata in più posizioni purché la variabile abbia sempre lo stesso scopo. Ad esempio, se dieci chiamate di funzione restituiscono un codice di errore, che viene gestito immediatamente per ogni chiamata, utilizzare una variabile e non 10. Ma non utilizzare la stessa variabile per cose completamente diverse. Come usare "nome" per il nome di un cliente e 10 righe in seguito usando la stessa variabile per il nome di una società, è un male e ti metterà nei guai. Peggio ancora, usando "customerName" per un nome cliente e 10 righe in seguito usando la stessa variabile "customerName" per un nome di società.

È importante sottolineare che nulla è una regola di ferro. Tutto ha vantaggi e svantaggi. Se le "migliori pratiche" suggeriscono una cosa e hai motivi per dire che è una cattiva idea nella tua situazione specifica, allora non farlo.


0

Innanzitutto, guarda il tuo ambiente di sviluppo. Se hai problemi con il debug perché hai cinque variabili in ambiti diversi con nomi identici e il debugger non ti mostra quale di queste variabili è quella di cui hai bisogno, quindi non utilizzare cinque variabili con lo stesso nome. Ci sono due modi per raggiungere questo obiettivo: utilizzare una variabile o utilizzare cinque nomi diversi.

Il debugger può anche rendere doloroso eseguire il debug di una funzione con molte variabili. Se una funzione con 20 variabili è più difficile da eseguire il debug di una con 16 variabili, allora potresti prendere in considerazione la sostituzione di 5 variabili con una. ("Potrebbe considerare" non è lo stesso di "dovrebbe sempre").

Va bene avere una variabile utilizzata in più posizioni purché la variabile abbia sempre lo stesso scopo. Ad esempio, se dieci chiamate di funzione restituiscono un codice di errore, che viene gestito immediatamente per ogni chiamata, utilizzare una variabile e non 10. Vi è un problema con questo: di solito, il compilatore ti dirà quando si utilizza una variabile non inizializzata. Ma qui, se leggi il codice di errore dopo la chiamata 6, ma la variabile non è stata effettivamente modificata dopo la chiamata 5, otterrai dati inutili senza che il compilatore ti avverta. Perché la variabile è stata inizializzata, con dati ora inutili.

È importante sottolineare che nulla è una regola di ferro. Tutto ha vantaggi e svantaggi. Se le "migliori pratiche" suggeriscono una cosa e hai motivi per dire che è una cattiva idea nella tua situazione specifica, allora non farlo.


-2

Utilizzare le variabili globali quando è necessario mantenere uno stato o memorizzare costanti. Riutilizzando le variabili si sta solo riutilizzando il nome che punta a una posizione in memoria. I nomi descrittivi sulle inizializzazioni possono solo guadagnare chiarezza (supponendo Java e nessun disturbo ossessivo compulsivo primitivo).

A meno che non ti piaccia l'offuscamento del codice a mano o irriti gli altri sviluppatori.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.