Dovremmo eliminare le variabili locali se possiamo?


95

Ad esempio, per mantenere una CPU attiva su Android, posso usare un codice come questo:

PowerManager powerManager = (PowerManager)getSystemService(POWER_SERVICE);
WakeLock wakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "abc");
wakeLock.acquire();

ma penso che le variabili locali powerManagere wakeLockpossano essere eliminate:

((PowerManager)getSystemService(POWER_SERVICE))
    .newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "MyWakelockTag")
    .acquire();

scena simile appare nella vista di avviso di iOS, ad esempio: da

UIAlertView *alert = [[UIAlertView alloc]
    initWithTitle:@"my title"
    message:@"my message"
    delegate:nil
    cancelButtonTitle:@"ok"
    otherButtonTitles:nil];
[alert show];

-(void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex{
    [alertView release];
}

per:

[[[UIAlertView alloc]
    initWithTitle:@"my title"
    message:@"my message"
    delegate:nil
    cancelButtonTitle:@"ok"
    otherButtonTitles:nil] show];

-(void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex{
    [alertView release];
}

È buona norma eliminare una variabile locale se viene utilizzata una sola volta nell'ambito?


95
Non necessariamente. A volte rende più chiaro il codice nell'utilizzo di variabili singole e, nella maggior parte dei linguaggi di programmazione decenti, i costi di runtime di tali variabili aggiuntive sono molto bassi (se presenti).
Robert Harvey,

75
Inoltre, rende più difficile scorrere il codice con un debugger. E devi anche essere sicuro (a seconda della lingua) che la prima espressione non è un NULL o un errore.
GrandmasterB

78
No, non lo è. In effetti, è buona norma introdurre variabili locali per spezzare catene di chiamate di metodo. È probabile che il codice macchina generato sia identico e il codice sorgente è quasi garantito per essere più leggibile, quindi migliore.
Kilian Foth,

48
Prova questo. Ora collega il debugger e prova a vedere lo stato di PowerManager o WakeLock. Realizza il tuo errore. Pensavo lo stesso ("che cosa succede a tutti questi locali?") Fino a quando non ho dovuto dedicare la maggior parte del mio tempo a indagare sul codice.
Faerindel,

42
Anche nel tuo esempio, la tua versione "eliminata" ha una barra di scorrimento e non si adatta completamente al mio schermo, il che rende molto più difficile da leggere.
Erik,

Risposte:


235

Il codice viene letto molto più spesso di quanto sia scritto, quindi dovresti avere pietà della povera anima che dovrà leggere il codice tra sei mesi (potresti essere tu) e cercare il codice più chiaro e più facile da capire. Secondo me, la prima forma, con variabili locali, è molto più comprensibile. Vedo tre azioni su tre righe, anziché tre azioni su una riga.

E se pensi di ottimizzare qualcosa eliminando le variabili locali, non lo sei. Un moderno compilatore inserirà powerManagerun registro 1 , indipendentemente dal fatto che venga utilizzata o meno una variabile locale, per chiamare il newWakeLockmetodo. Lo stesso vale per wakeLock. Quindi in entrambi i casi si ottiene lo stesso codice compilato.

1 Se tra la dichiarazione e l'uso della variabile locale fosse presente un sacco di codice, questo potrebbe andare nello stack, ma è un dettaglio minore.


2
Non puoi sapere se c'è molto codice, l'ottimizzatore potrebbe includere alcune funzioni ... Altrimenti, concordato, cercare prima la leggibilità è la mossa giusta.
Matthieu M.

2
Bene, penso il contrario, se vedo una variabile locale inizializzare multipli volte su ogni funzione in cui viene usata invece di essere un attributo quando può essere, cercherò perché, fondamentalmente leggerò a fondo le righe e le confronterò solo con assicurati che siano uguali. Quindi perderò tempo.
Walfrat,

15
@Walfrat Le variabili locali vengono inizializzate più volte? Ahia. Nessuno ha suggerito di riutilizzare la gente del posto :)
Luaan il

32
I membri di @Walfrat generano effetti collaterali e devono essere utilizzati solo quando si desidera mantenere lo stato tra le chiamate ai membri pubblici. Questa domanda sembra occuparsi dell'uso locale per la memorizzazione temporanea di calcoli intermedi.
Gusdor,

4
D: Se possibile, dovremmo eliminare le variabili locali? A: No.
simon,

94

Alcuni commenti altamente votati lo hanno affermato, ma nessuna delle risposte che ho visto lo ha fatto, quindi lo aggiungerò come risposta. Il tuo fattore principale nel decidere questo problema è:

Debuggability

Spesso, gli sviluppatori impiegano molto più tempo e sforzi nel debug rispetto alla scrittura di codice.

Con le variabili locali, puoi:

  • Punto di interruzione sulla linea in cui è assegnato (con tutte le altre decorazioni del punto di interruzione, come il punto di interruzione condizionale, ecc ...)

  • Ispeziona / guarda / stampa / cambia il valore della variabile locale

  • Problemi di cattura dovuti a calchi.

  • Tracce di stack leggibili (la riga XYZ ha un'operazione anziché 10)

Senza variabili locali, tutte le attività sopra descritte sono molto più difficili, estremamente difficili o assolutamente impossibili, a seconda del debugger.

Come tale, segui la famigerata massima (scrivi il codice in un modo come se lo sviluppatore successivo a mantenerlo dopo te stesso fosse un folle pazzo che sa dove vivi) e sbaglia dal lato della debuggabilità più semplice , nel senso che usa le variabili locali .


20
Vorrei aggiungere che stacktraces sono molto meno utili quando ci sono molte chiamate su una sola linea. Se hai un'eccezione puntatore nullo sulla linea 50 e ci sono 10 chiamate su quella linea non restringe molto le cose. In un'applicazione di produzione, questa sarà spesso la maggior parte delle informazioni ottenute da un rapporto sui difetti.
JimmyJames

3
Anche passare attraverso il codice è molto più difficile. Se c'è call () -> call () -> call () -> call (), è difficile entrare nella terza chiamata del metodo. Molto più facile se ci sono quattro variabili locali
gnasher729

3
@FrankPuffer - abbiamo a che fare con il mondo reale. Dove i debugger non fanno ciò che proponi.
DVK,

2
@DVK: In realtà ci sono più debugger di quanto pensassi che ti permettono di ispezionare o guardare qualsiasi espressione. MS Visual Studio (dalla versione 2013) ha questa funzionalità per C ++ e C #. Eclipse ce l'ha per Java. In un altro commento, Faerindel ha menzionato IE11 per JS.
Frank Puffer,

4
@DVK: Sì, molti debugger del mondo reale non fanno ciò che propongo. Ma questo non ha nulla a che fare con la prima parte del mio commento. Trovo folle supporre che la persona che manterrà il mio codice interagirà principalmente con esso tramite un debugger. I debugger sono ottimi per determinati scopi ma se ottengono lo strumento principale per l'analisi del codice, direi che qualcosa è seriamente sbagliato e proverei a risolverlo invece di rendere il codice più debuggabile.
Frank Puffer,

47

Solo se semplifica la comprensione del codice. Nei tuoi esempi, penso che sia più difficile da leggere.

L'eliminazione delle variabili nel codice compilato è un'operazione banale per qualsiasi compilatore rispettabile. È possibile ispezionare l'output manualmente per verificare.


1
Ciò ha tanto a che fare con lo stile quanto con l'uso delle variabili. La domanda è stata ora modificata.
Jodrell,

29

La tua domanda "è una buona pratica eliminare una variabile locale se viene usata una sola volta nell'ambito?" sta testando criteri sbagliati. L'utilità di una variabile locale non dipende dal numero di volte in cui viene utilizzata, ma dal fatto che renda il codice più chiaro. L'etichettatura di valori intermedi con nomi significativi può migliorare la chiarezza in situazioni come quella che presenti poiché scompone il codice in blocchi più piccoli, più digeribili.

A mio avviso, il codice non modificato che hai presentato è più chiaro del tuo codice modificato e quindi dovrebbe essere lasciato invariato. In effetti, prenderei in considerazione l'estrazione di una variabile locale dal codice modificato per migliorare la chiarezza.

Non mi aspetto alcun impatto sulle prestazioni dalle variabili locali e, anche se ce n'è uno, è probabile che sia troppo piccolo per essere preso in considerazione, a meno che il codice non sia in un ciclo molto stretto in una parte critica della velocità del programma.


Penso che abbia molto a che fare con lo stile e l'uso dello spazio bianco come qualsiasi altra cosa. La domanda è stata modificata.
Jodrell,

15

Può essere.

Personalmente esiterei ad eliminare le variabili locali se è coinvolto un typecast. Trovo la tua versione compatta meno leggibile poiché il numero di parentesi inizia ad avvicinarsi a un limite mentale che ho. Introduce anche un nuovo set di parentesi che non era necessario nella versione leggermente più dettagliata usando una variabile locale.

L'evidenziazione della sintassi fornita dall'editor di codice potrebbe mitigare tali preoccupazioni in una certa misura.

Ai miei occhi, questo è il miglior compromesso:

PowerManager powerManager = (PowerManager)getSystemService(POWER_SERVICE);
powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "abc").acquire();

Mantenendo così una variabile locale e abbandonando l'altra. In C # userei la parola chiave var sulla prima riga poiché il typecast fornisce già le informazioni sul tipo.


13

Sebbene io accetti la validità delle risposte a favore delle variabili locali, interpreterò l'avvocato del diavolo e presenterò una visione contrarian.

Personalmente sono in qualche modo contrario all'utilizzo delle variabili locali puramente per ciò che equivale a scopi di documentazione, anche se quella stessa ragione indica che la pratica ha valore: le variabili locali effettivamente pseudo-documentano il codice.

Nel tuo caso, il problema principale è il rientro e non l'assenza di variabili. Puoi (e dovresti) formattare il codice come segue:

((PowerManager)getSystemService(POWER_SERVICE))
        .newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,"MyWakelockTag")
        .acquire();

Confrontalo con la versione con le variabili locali:

PowerManager powerManager=(PowerManager)getSystemService(POWER_SERVICE);
WakeLock wakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,"abc");
wakeLock.acquire();

Con le variabili locali: i nomi aggiungono alcune informazioni al lettore e i tipi sono chiaramente specificati, ma le chiamate ai metodi effettivi sono meno visibili e (secondo me) non leggono così chiaramente.

Senza usare le variabili locali: è più conciso e le chiamate al metodo sono più visibili, ma potresti chiedere maggiori informazioni su ciò che viene restituito. Alcuni IDE possono mostrartelo comunque.

Tre ulteriori commenti:

  1. A mio avviso, l'aggiunta di codice che non ha alcun uso funzionale a volte può essere fonte di confusione in quanto il lettore deve rendersi conto che non ha effettivamente alcun uso funzionale ed è semplicemente lì per "documentazione". Ad esempio, se questo metodo fosse lungo 100 righe non sarebbe ovvio che le variabili locali (e quindi il risultato della chiamata al metodo) non sarebbero state richieste in un secondo momento a meno che non si leggesse l'intero metodo.

  2. L'aggiunta delle variabili locali significa che è necessario specificare i loro tipi e questo introduce una dipendenza nel codice che altrimenti non ci sarebbe. Se il tipo restituito dei metodi è cambiato in modo banale (ad esempio, è stato rinominato) dovresti aggiornare il tuo codice, mentre senza le variabili locali non lo faresti.

  3. Il debug potrebbe essere più semplice con le variabili locali se il debugger non mostra valori restituiti dai metodi. Ma la soluzione è quella di correggere le carenze nei debugger, non cambiare il codice.


Per quanto riguarda i tuoi ulteriori commenti: 1. Questo non dovrebbe essere un problema se stai seguendo la convenzione che le variabili locali sono dichiarate il più vicino possibile al luogo in cui vengono utilizzate e stai mantenendo i tuoi metodi per una durata ragionevole. 2. Non in un linguaggio di programmazione con deduzione del tipo. 3. Il codice ben scritto spesso non richiede affatto un debugger.
Robert Harvey,

2
Il tuo primo esempio di codice funziona solo se stai creando i tuoi oggetti usando interfacce fluide o un "builder", schemi che non userei ovunque nel mio codice, ma solo selettivamente.
Robert Harvey,

1
Penso che la domanda presuma che le variabili locali siano funzionalmente ridondanti e che quindi sia necessario il tipo di interfaccia per il caso. Probabilmente potremmo ottenere la rimozione della gente del posto se fosse diversamente attraverso varie contorsioni, ma avevo in mente che stavamo esaminando il caso semplice.
rghome

1
Trovo la tua variante ancora peggiore per la leggibilità. Potrei essere stato esposto troppo a VB.net, ma la mia prima volta, quando ho visto il tuo esempio, è "Dov'è finita l'istruzione WITH? L'ho cancellata per errore?" Ho bisogno di esaminare due volte quello che sta succedendo e questo non va bene quando devo rivisitare il codice molti mesi dopo.
Tonny,

1
@Tonny per me, è più leggibile: i locali non aggiungono nulla di non ovvio dal contesto. Ho Java in testa, quindi niente withdichiarazioni. Sarebbe normali convenzioni di formattazione in Java.
dal

6

C'è una tensione di motivazioni qui. L'introduzione di variabili temporanee può facilitare la lettura del codice. Ma possono anche prevenire e rendere più difficile la visualizzazione di altri possibili refactoring, come Estrai metodo e Sostituisci temp con query . Questi ultimi tipi di refactoring, se del caso, offrono spesso benefici molto maggiori rispetto alla variabile temp.

Sulle motivazioni di questi ultimi refactoring, Fowler scrive :

"Il problema con le temperature è che sono temporanee e locali. Poiché possono essere viste solo nel contesto del metodo in cui vengono utilizzate, le temperature tendono a incoraggiare metodi più lunghi, perché è l'unico modo per raggiungere la temperatura. sostituendo la temp con un metodo di query, qualsiasi metodo nella classe può ottenere le informazioni. Ciò aiuta molto a trovare un codice più pulito per la classe. "

Quindi sì, usa temps se rendono il codice più leggibile, specialmente se questa è una norma locale per te e il tuo team. Ma tieni presente che a volte puoi rendere più difficile individuare miglioramenti alternativi più grandi. Se riesci a sviluppare la tua capacità di percepire quando vale la pena andare senza tali temperature e sentirti più a tuo agio nel farlo, probabilmente è una buona cosa.

FWIW Ho personalmente evitato di leggere il libro "Refactoring" di Fowler per dieci anni perché immaginavo che non ci fosse molto da dire su argomenti relativamente semplici. Ho sbagliato completamente. Quando alla fine l'ho letto, ha cambiato le mie pratiche quotidiane di codifica, tanto per il meglio.


1
Bella risposta. Il miglior codice che ho scritto (e visto da altri) spesso aveva molti metodi piccoli (2, 3 righe) che potevano prendere il posto di tali variabili temporanee. Correlato è questo controverso assunto che i metodi privati ​​puzzano ... Ben pensato e l'ho trovato spesso vero.
Stijn de Witt,

I temp in questa domanda si riferiscono già a funzioni, quindi questa risposta è irrilevante per la domanda dei PO.
user949300

@ user949300 Non penso che sia irrilevante. Sì, le temp nell'esempio specifico dell'OP sono i valori di ritorno da funzioni o metodi. Ma l'OP è molto chiaro che è solo uno scenario esemplificativo. La vera domanda è molto più generale "dovremmo eliminare le variabili temporanee quando possiamo?"
Jonathan Hartley,

1
OK, sono venduto, ** ho provato a ** cambiare il mio voto. Ma spesso quando vado oltre la portata limitata della domanda di OP, mi vengono oscurati. Quindi può essere volubile ... :-). Ehm, non posso cambiare il mio voto fino alla tua modifica, qualunque cosa ...
user949300

@ user949300 Holy cow! Una persona che cambia idea prendendo in considerazione attentamente i problemi! Lei, signore, è una rarità e io mi tolgo il berretto.
Jonathan Hartley,

3

Bene, è una buona idea eliminare le variabili locali se è possibile rendere il codice più leggibile in tal modo. Quel lungo one-liner non è leggibile, ma segue uno stile OO piuttosto prolisso. Se potessi ridurlo a qualcosa del genere

acquireWakeLock(POWER_SERVICE, PARTIAL, "abc");

allora direi che probabilmente sarebbe una buona idea. Forse puoi introdurre metodi di aiuto per ridurlo a qualcosa di simile; se codice come questo appare più volte, potrebbe valere la pena.


2

Consideriamo qui la Legge di Demetra . Nell'articolo di Wikipedia su LoD si afferma quanto segue:

La Legge di Demetra per le funzioni richiede che un metodo m di un oggetto O possa invocare solo i metodi dei seguenti tipi di oggetti: [2]

  1. O stesso
  2. parametri di m
  3. Qualsiasi oggetto creato / istanziato entro m
  4. Oggetti componenti diretti di O.
  5. Una variabile globale, accessibile da O, nell'ambito di m

Una delle conseguenze derivanti dal seguire questa Legge è che dovresti evitare di invocare metodi di oggetti restituiti da altri metodi in una lunga stringa tratteggiata insieme, come mostrato nel secondo esempio sopra:

((PowerManager)getSystemService(POWER_SERVICE)).newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,"MyWakelockTag").acquire();

È davvero difficile capire cosa stia facendo. Per capirlo devi capire cosa fa ogni procedura, quindi decifrare quale funzione viene chiamata su quale oggetto. Il primo blocco di codice

PowerManager powerManager=(PowerManager)getSystemService(POWER_SERVICE);
WakeLock wakeLock=powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,"abc");
wakeLock.acquire();

mostra chiaramente cosa stai cercando di fare: stai ottenendo un oggetto PowerManager, ottenendo un oggetto WakeLock da PowerManager, quindi acquisendo wakeLock. Quanto sopra segue la regola n. 3 di LoD: stai istanziando questi oggetti nel tuo codice e quindi puoi usarli per fare ciò di cui hai bisogno.

Forse un altro modo di pensare è di ricordare che quando si crea un software è necessario scrivere per chiarezza, non per brevità. Il 90% di tutto lo sviluppo del software è di manutenzione. Non scrivere mai un pezzo di codice che non saresti felice di mantenere.

Buona fortuna.


3
Sarei interessato a come la sintassi fluida si adatta a questa risposta. Con una formattazione corretta, la sintassi fluida è altamente leggibile.
Gusdor,

12
Non è quello che significa "Legge di Demetra". La Legge di Demetra non è un esercizio di conteggio dei punti; significa essenzialmente "parla solo con i tuoi amici immediati".
Robert Harvey,

5
Accedere agli stessi metodi e membri tramite una variabile intermedia è ancora una violazione altrettanto grave della legge di Demetra. L'hai appena oscurato, non risolto.
Jonathan Hartley il

2
In termini di "Legge di Demetra", entrambe le versioni sono ugualmente "cattive".
Hulk,

@Gusdor ha concordato, questo più un commento sullo stile nell'esempio della domanda. La domanda è stata ora modificata.
Jodrell,

2

Una cosa da notare è che il codice viene letto frequentemente, a "profondità" diverse. Questo codice:

PowerManager powerManager = (PowerManager)getSystemService(POWER_SERVICE);
WakeLock wakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "abc");
wakeLock.acquire();

è facile "scremare". Sono 3 affermazioni. Per prima cosa ci viene in mente un PowerManager. Quindi arriviamo a WakeLock. Poi abbiamo acquirela wakeLock. Posso vederlo davvero facilmente solo guardando l'inizio di ogni riga; le assegnazioni di variabili semplici sono davvero facili da riconoscere parzialmente come "Digitare varName = ..." e sfiorare mentalmente il "...". Allo stesso modo l'ultima affermazione non è ovviamente la forma del compito, ma coinvolge solo due nomi, quindi la "sostanza principale" è immediatamente evidente. Spesso è tutto ciò che avrei bisogno di sapere se stavo solo cercando di rispondere "cosa fa questo codice?" a un livello elevato.

Se sto inseguendo un bug sottile che penso sia qui, allora ovviamente dovrò andare su questo in modo molto più dettagliato e in realtà ricorderò i "...". Ma la struttura separata delle istruzioni mi aiuta ancora a fare quella frase alla volta (particolarmente utile se ho bisogno di approfondire l'implementazione delle cose chiamate in ogni dichiarazione; quando torno ho capito perfettamente "un'unità" e può quindi passare all'istruzione successiva).

((PowerManager)getSystemService(POWER_SERVICE))
    .newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "MyWakelockTag")
    .acquire();

Ora è tutta una frase. La struttura di livello superiore non è così facile da leggere; nella versione originale dell'OP, senza interruzioni di riga e rientri per comunicare visivamente qualsiasi struttura, avrei dovuto contare le parentesi per decodificarlo in una sequenza di 3 passaggi. Se alcune delle espressioni multiparte sono nidificate l'una nell'altra anziché disposte come una catena di chiamate di metodo, allora potrebbe comunque apparire simile a questo, quindi devo stare attento a fidarmi di ciò senza contare le parentesi. E se mi fido del rientro e guardo avanti fino all'ultima cosa come il punto presunto di tutto ciò, cosa .acquire()mi dice da solo?

A volte, però, può essere quello che vuoi. Se applico la trasformazione a metà strada e scrivo:

WakeLock wakeLock =
     ((PowerManeger)getSystemService(POWER_SERVICE))
    .newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "MyWakeLockTage");
wakeLock.acquire();

Ora questo comunica a una breve scrematura "prendi a WakeLock, allora acquire". Ancora più semplice della prima versione. È immediatamente ovvio che la cosa acquisita è a WakeLock. Se ottenere il PowerManagerè solo un sotto-dettaglio che è abbastanza insignificante fino al punto di questo codice, ma wakeLockè importante, allora potrebbe effettivamente aiutare a seppellire la PowerManagerroba quindi è naturale passarci sopra se stai solo cercando di ottenere rapidamente un idea di cosa fa questo codice. E non nominando, comunica che viene usato solo una volta, e talvolta lo è ciò che è importante (se il resto dell'ambito è molto lungo, dovrei leggere tutto questo per dire se è mai stato usato di nuovo; sebbene l'uso di sotto-ambiti espliciti possa essere un altro modo per affrontarlo, se la tua lingua li supporta).

Il che fa capire che tutto dipende dal contesto e da cosa vuoi comunicare. Come per la scrittura di prosa in linguaggio naturale, ci sono sempre molti modi per scrivere una determinata parte di codice che sono sostanzialmente equivalenti in termini di contenuto informativo. Come con la scrittura in prosa in linguaggio naturale, come si sceglie tra di loro dovrebbero generalmente non essere quello di applicare regole meccanicistiche come "eliminare ogni variabile locale che si verifica solo una volta". Piuttosto comescegli di scrivere il tuo codice enfatizzerà alcune cose e ne de-enfatizzerà altre. Dovresti sforzarti di fare queste scelte consapevolmente (inclusa la scelta di scrivere codice meno leggibile per motivi tecnici a volte), in base a ciò che vuoi davvero sottolineare. Pensa in particolare a ciò che servirà ai lettori che hanno solo bisogno di "capire il codice" del tuo codice (a vari livelli), dal momento che ciò accadrà molto più spesso di una lettura espressione per espressione molto ravvicinata.


Per me, anche se non conosco l'API, è molto ovvio cosa fa il codice, anche senza le variabili. getSystemService(POWER_SERVICE)ottiene il power manager. .newWakeLockottiene una sveglia. .acquirelo acquisisce. OK, non conosco tutti i tipi, ma posso scoprirlo nell'IDE se ne ho bisogno.
dal

Potrebbe essere ovvio per te cosa dovrebbe fare il codice , ma non hai idea di cosa faccia effettivamente. Se sto cercando un bug, tutto quello che so è che qualche codice da qualche parte non fa quello che dovrebbe fare, e devo trovare quale codice.
gnasher729,

@ gnasher729 Sì. La caccia agli insetti è stato un esempio di cui avrei dovuto leggere attentamente tutti i dettagli. E una delle cose che aiuta davvero a trovare il codice che non sta facendo quello che dovrebbe fare è quella di essere in grado di vedere facilmente qual era l'intento dell'autore originale.
Ben

quando torno ho capito perfettamente "una unità" e posso quindi passare alla frase successiva. In realtà no. In effetti le variabili locali impediscono quella piena comprensione. Perché stanno ancora indugiando ... occupando spazio mentale ... cosa succederà loro nelle prossime 20 dichiarazioni ... rullo di tamburi ... Senza gente del posto saresti sicuro che gli oggetti fossero spariti e impossibile fare qualsiasi cosa con loro nelle prossime righe. Non c'è bisogno di ricordare su di loro. Mi piace il returnpiù rapidamente possibile con i metodi, per lo stesso motivo.
Stijn de Witt,

2

Questo è persino un antipasto con il suo nome: Train Wreck . Sono già stati indicati diversi motivi per evitare la sostituzione:

  • Più difficile da leggere
  • Più difficile da eseguire il debug (sia per guardare le variabili e rilevare le posizioni delle eccezioni)
  • Violazione della legge di Demetra (LoD)

Considera se questo metodo sa troppo dagli altri oggetti. Il concatenamento dei metodi è un'alternativa che potrebbe aiutarti a ridurre l'accoppiamento.

Ricorda inoltre che i riferimenti agli oggetti sono davvero economici.


Ehm il codice modificato non sta facendo il concatenamento del metodo? EDIT leggi l'articolo collegato quindi vedo la differenza ora. Articolo abbastanza buono grazie!
Stijn de Witt,

Grazie per averlo recensito. Ad ogni modo, il metodo del metodo potrebbe funzionare in alcuni casi mentre lasciare la variabile potrebbe essere la decisione appropriata. È sempre bene sapere perché le persone non sono d'accordo con la tua risposta.
Borjab,

Immagino che l'opposto di "Train Wreck" sia "Local Line". È quel treno tra due città principali che si ferma in ogni villaggio di campagna nel caso in cui qualcuno voglia salire o scendere, anche se la maggior parte dei giorni nessuno lo fa.
rghome

1

La domanda dichiarata è "Dovremmo eliminare le variabili locali se possiamo"?

No, non dovresti eliminarlo solo perché puoi.

Dovresti seguire le linee guida per la codifica nel tuo negozio.

Per la maggior parte, le variabili locali rendono il codice più semplice da leggere ed eseguire il debug.

Mi piace quello che hai fatto PowerManager powerManager. Per me un minuscolo della classe significa che è solo un uso una volta.

Quando non dovresti, è se la variabile si terrà su risorse costose. Molte lingue hanno la sintassi per una variabile locale che deve essere ripulita / rilasciata. In C # sta usando.

using(SQLconnection conn = new SQLconnnection())
{
    using(SQLcommand cmd = SQLconnnection.CreateCommand())
    {
    }
}

Questo non è in realtà correlato alle variabili locali ma alla pulizia delle risorse ... Non sono esperto di C # ma sarei sorpreso se using(new SQLConnection()) { /* ... */ }non fosse anche legale (se sarebbe utile è una questione diversa :).
Stijn de Witt,

1

Un aspetto importante non è stato menzionato nelle altre risposte: ogni volta che aggiungi una variabile, introduci uno stato mutabile. Questo di solito è una cosa negativa perché rende il codice più complesso e quindi più difficile da capire e testare. Naturalmente, minore è l'ambito della variabile, minore è il problema.

Quello che vuoi in realtà non è una variabile il cui valore può essere modificato ma una costante temporanea. Pertanto, considera di esprimerlo nel tuo codice se la tua lingua lo consente. In Java puoi usare finale in C ++ puoi usare const. Nella maggior parte dei linguaggi funzionali, questo è il comportamento predefinito.

È vero che le variabili locali sono il tipo meno dannoso di stato mutabile. Le variabili membro possono causare molti più problemi e le variabili statiche sono ancora peggio. Tuttavia trovo importante esprimere nel tuo codice nel modo più preciso possibile ciò che dovrebbe fare. E c'è un'enorme differenza tra una variabile che potrebbe essere modificata in seguito e un semplice nome per un risultato intermedio. Quindi, se la tua lingua ti consente di esprimere questa differenza, fallo e basta.


2
Non ho declassato la tua risposta, ma immagino che sia correlato al fatto che le variabili locali non sono generalmente considerate "stato" nei linguaggi imperativi a meno che tu non stia parlando di una sorta di metodo a lungo termine. Concordo sull'uso di final / const come best practice, ma è piuttosto improbabile che l'introduzione di una variabile per interrompere semplicemente una chiamata incatenata porti a problemi causati dallo stato mutevole. In effetti, l'uso di variabili locali aiuta a gestire lo stato mutabile. Se un metodo può restituire valori diversi in momenti diversi, in caso contrario potresti finire con alcuni bug davvero interessanti.
JimmyJames,

@JimmyJames: ho aggiunto alcune spiegazioni alla mia risposta. Ma c'è una parte del tuo commento che non ho capito: "l'uso di variabili locali aiuta a gestire lo stato mutevole". Potresti spiegarlo?
Frank Puffer

1
Ad esempio, diciamo che devo controllare un valore e se è oltre 10, lancia un avviso. Supponiamo che questo valore provenga dal metodo getFoo(). Se evito una dichiarazione locale, if(getFoo() > 10) alert(getFoo());finirò con Ma getFoo () potrebbe restituire valori diversi sulle due diverse chiamate. Potrei inviare un avviso con un valore inferiore o uguale a 10, che è al massimo fonte di confusione e tornerà da me come difetto. Questo genere di cose diventa più importante con la concorrenza. L'assegnazione locale è atomica.
JimmyJames,

Ottimo punto Forse la ragione per cui non mi piace questi locali .... Avete intenzione di fare qualcosa con quel PowerManagercaso dopo aver chiamato questo metodo? Fammi controllare il resto del metodo .... mmm ok no. E questa WakeLockcosa che hai ... cosa ci fai (scansionando il resto del metodo ancora una volta) ... mmm di nuovo niente ... ok quindi perché sono lì? Oh sì, dovrebbe essere più leggibile ... ma senza di loro sono sicuro che non li usi più, quindi non devo leggere il resto del metodo.
Stijn de Witt,

In un recente discorso, l'oratore ha sostenuto che il modo migliore per dimostrare che una variabile è definitiva è scrivere metodi brevi in ​​cui è ovvio che la variabile non cambia . Se finalè necessaria una variabile locale in un metodo, il metodo è troppo lungo.
user949300
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.