Devo utilizzare le parentesi nelle istruzioni logiche anche dove non necessario?

91

Diciamo che ho una condizione booleana a AND b OR c AND d e sto usando una lingua in cui AND ha un precedente di ordine operativo superiore a OR . Potrei scrivere questa riga di codice:

If (a AND b) OR (c AND d) Then ...

Ma in realtà, è equivalente a:

If a AND b OR c AND d Then ...

Ci sono argomenti a favore o contro che includono le parentesi estranee? L'esperienza pratica suggerisce che vale la pena includerli per la leggibilità? O è un segno che uno sviluppatore ha bisogno di sedersi e diventare sicuro delle basi del proprio linguaggio?

    
posta Jeff Bridgman 11.06.2013 - 16:59
fonte

14 risposte

104

I buoni sviluppatori si sforzano di scrivere codice che cancella e corregge . Le parentesi in condizionale, anche se non sono strettamente necessarie, aiutano con entrambi.

Per quanto riguarda la chiarezza , pensate alle parentesi come i commenti nel codice: non sono strettamente necessari, e in teoria uno sviluppatore competente dovrebbe essere in grado di capire il codice senza di essi. Eppure, questi segnali sono estremamente utili, perché:

  • Riducono il lavoro necessario per comprendere il codice.
  • Forniscono conferma dell'intenzione dello sviluppatore.

Inoltre, le parentesi extra, proprio come le indentazioni, gli spazi bianchi e altri standard di stile, aiutano a organizzare visivamente il codice in modo logico.

Come per correttezza , le condizioni senza parentesi sono una ricetta per errori stupidi. Quando accadono, possono essere bug difficili da trovare, perché spesso una condizione errata si comporta correttamente la maggior parte delle volte e solo occasionalmente fallisce.

E anche se hai ragione, la prossima persona a lavorare sul tuo codice non può, aggiungendo errori all'espressione o fraintendendo la tua logica e quindi aggiungendo errori altrove (come giustamente fa notare LarsH).

Uso sempre le parentesi per le espressioni che combinano and e or (e anche per operazioni aritmetiche con problemi di precedenza simili).

    
risposta data 12.06.2013 - 15:35
fonte
89

Importa meno se tu hai fiducia nella tua comprensione della lingua. Ciò che conta di più è la comprensione del linguaggio del n00b che ti segue.

Scrivi il tuo codice nel modo più chiaro possibile. Parentesi aggiuntiva spesso (ma non sempre) aiuto. Mettere solo una frase su una linea aiuta spesso. La coerenza nello stile di codifica spesso aiuta.

C'è una cosa come troppe parentesi, ma è una di quelle situazioni in cui non avrai bisogno di consigli - lo saprai quando lo vedrai. A quel punto, rifatta il tuo codice per ridurre la complessità dell'istruzione piuttosto che rimuovere le parentesi.

    
risposta data 06.03.2017 - 10:55
fonte
27

Dovresti sempre usare le parentesi ... non controlli l'ordine di precedenza ... lo sviluppatore del compilatore lo fa. Ecco una storia che mi è accaduta riguardo al non utilizzo delle parentesi. Ciò ha colpito centinaia di persone per un periodo di due settimane.

Motivo mondiale reale

Ho ereditato un'applicazione principale. Un giorno, dal nulla, ha smesso di funzionare. Questo è tutto ... puff si è appena fermato.

Il mio compito era di farlo funzionare il più velocemente possibile. Il codice sorgente non era stato modificato per due anni, ma all'improvviso si è fermato. Ho provato a compilare il codice e si è rotto sulla linea XX. Ho guardato la riga XX e non saprei dire cosa avrebbe fatto rompere la linea XX. Ho chiesto le specifiche dettagliate per questa applicazione e non ce n'erano. La linea XX non era il colpevole.

Ho stampato il codice e ho iniziato a rivederlo dall'alto verso il basso. Ho iniziato a creare un diagramma di flusso di ciò che stava accadendo. Il codice era così contorto che non riuscivo nemmeno a capirlo. Ho rinunciato a cercare di diagrammarlo. Avevo paura di apportare modifiche senza sapere in che modo tale modifica avrebbe influito sul resto del processo, soprattutto dal momento che non avevo i dettagli di ciò che l'applicazione faceva o dov'era nella catena delle dipendenze.

Quindi, ho deciso di iniziare nella parte superiore del codice sorgente e aggiungere whitespce e line brakes per rendere il codice più leggibile. Ho notato che, in alcuni casi, c'erano condizioni che combinavano AND e OR e non era chiaramente distinguibile tra i dati che erano ANDed e quali dati venivano elaborati. Così ho iniziato a mettere le parentesi attorno alle condizioni AND e OR per renderle più leggibili.

Mentre andavo piano piano a ripulirlo, avrei periodicamente salvato il mio lavoro. A un certo punto ho provato a compilare il codice e una cosa strana è accaduta. L'errore era saltato oltre la linea di codice originale e ora era più in basso. Così ho continuato, spacciando le condizioni AND e OR con i parens. Quando ho finito di ripulirlo ha funzionato. Vai alla figura.

Ho quindi deciso di visitare il negozio delle operazioni e chiedere loro se avessero installato recentemente nuovi componenti sul frame principale. Hanno detto di sì, abbiamo recentemente aggiornato il compilatore. Hmmmm.

Risulta che il vecchio compilatore ha valutato l'espressione da sinistra a destra indipendentemente. La nuova versione del compilatore ha anche valutato le espressioni da sinistra a destra, ma il codice ambiguo, il che significa che la combinazione non chiara di AND e OR non può essere risolta.

Lezione Ho imparato da questo ... SEMPRE, SEMPRE, utilizzare SEMPRE le condizioni AND e le condizioni OR separate quando sono usate in combinazione tra loro.

Esempio semplificato

Prodotto IF = 191 OR Prodotto = 193 AND Modello="ABC" O Prodotto = 201 OR Prodotto = 202 AND Modello="DEF" ... (codice cosparso di molti di questi)

Questa è una versione semplificata di ciò che ho incontrato. Esistevano anche altre condizioni con istruzioni logiche booleane composte.

Ricordo di averlo fatto notare a:
IF ((Prodotto = 191 OR Prodotto = 193) AND Modello="ABC") OR ((Prodotto = 201 OR Prodotto = 202) E Modello="DEF") ...
Non potevo riscriverlo perché non c'erano specifiche. L'autore originale era sparito da tempo. Ricordo una pressione intensa. Un'intera nave mercantile era bloccata in porto e non poteva essere caricata perché questo piccolo programma non funzionava. Nessun avvertimento. Nessuna modifica al codice sorgente. Mi è solo venuto in mente di chiedere alle Operazioni di rete se hanno modificato qualcosa dopo aver notato che l'aggiunta di Paren ha modificato gli errori.

    
risposta data 20.10.2018 - 12:40
fonte
17

Sì, se ci sono misti "e" e "o".

Buona idea anche per () cosa è logicamente un assegno.

È meglio usare le funzioni di predicato ben definite e sfrattare la maggior parte dei controlli e delle condizioni, lasciando se sia semplice e leggibile.

    
risposta data 11.06.2013 - 16:21
fonte
11

Le parentesi sono semanticamente ridondanti, quindi il compilatore non si preoccupa, ma questa è una falsa pista: la vera preoccupazione è la leggibilità e la comprensione del programmatore.

Prenderò qui la posizione radicale e dare un "no" abbondante alle parentesi in a AND b OR c AND d . Ogni programmatore dovrebbe sapere a memoria che la precedenza nelle espressioni booleane è NOT > AND > O , proprio come ricordare Per favore scusa My Dear Aunt Sally per espressioni algebriche. La punteggiatura ridondante aggiunge semplicemente confusione visiva la maggior parte del tempo nel codice senza alcun vantaggio nella leggibilità del programmatore.

Inoltre, se usi sempre le parentesi nelle espressioni logiche e algebriche, perdi la possibilità di usarle come marcatore per "qualcosa di complicato sta accadendo qui - guarda fuori!" Cioè, nei casi in cui si desidera sovrascrivere la precedenza predefinita e avere un'ulteriore valutazione prima della moltiplicazione, o OR prima di AND, le parentesi sono una bella bandiera rossa per il programmatore successivo. Troppo uso di loro quando non sono necessari, e tu diventi il Ragazzo che pianse Lupo.

Farei un'eccezione per qualsiasi cosa al di fuori del regno dell'algebra (booleano o meno), come le espressioni del puntatore in C, dove qualcosa di più complicato di idiomi standard come *p++ o p = p->next probabilmente dovrebbe essere parentesi per mantenere il dereferenziamento e il diritto aritmetico. E, naturalmente, nulla di tutto questo si applica a linguaggi come Lisp, Forth o Smalltalk che usano una qualche forma di notazione polacca per le espressioni; ma per la maggior parte delle lingue tradizionali, la precedenza logica e aritmetica è totalmente standardizzata.

    
risposta data 11.06.2013 - 20:37
fonte
8

Come la vedo io:

Pro:

  • L'ordine delle operazioni è esplicito.
  • Ti protegge dai futuri sviluppatori che non comprendono l'ordine delle operazioni.

Contro:

  • Può risultare in un codice ingombrante e di difficile lettura

NO Pro:

NO Contro:

  • L'ordine delle operazioni è implicito
  • Il codice è meno gestibile per gli sviluppatori senza una buona comprensione dell'ordine delle operazioni.
risposta data 11.06.2013 - 16:38
fonte
3

Are there any arguments in for or against including the extraneous parentheses? Does practical experience suggest that it is worth including them for readability? Or is it a sign that a developer needs to really sit down and become confident in the basics of their language?

Se nessun altro avrebbe mai dovuto guardare di nuovo il mio codice, non credo che mi interesserebbe.

Ma, dalla mia esperienza:

  • Di tanto in tanto guardo il mio codice (a volte anni dopo averlo scritto)
  • Gli altri a volte guardano il mio codice
    • O devi persino estenderlo / risolverlo!
  • Né io né l'altro mi ricordo esattamente cosa stavo pensando scrivendolo
  • Scrittura criptica "ridimensiona il numero dei caratteri" il codice danneggia la leggibilità

Lo faccio quasi sempre perché mi fido della mia capacità di leggere velocemente e di non commettere piccoli errori molto più con parents che nient'altro.

Nel tuo caso, farei quasi sicuramente qualcosa del tipo:

if (a AND b) then ab = true
if (c AND d) then cd = true
If (ab OR cd) Then ...

Sì, è più codice. Sì, posso invece fare fancy bool operator. No, non mi piace l'opportunità di sfiorare il codice di 1+ anni in futuro, interpretando male gli operatori bool. Cosa succede se scrivevo codice in una lingua che aveva una precedenza AND / OR diversa e dovevo fare un salto indietro per risolvere il problema? Ho intenzione di andare, "aha! Mi ricordo di questa piccola cosa intelligente che ho fatto! Non ho dovuto includere Parens quando ho scritto questo l'anno scorso, buona cosa che ricordo ora!" se ciò accade (o peggio, qualcun altro che non era a conoscenza di questa intelligenza o è stato gettato in una situazione di tipo "aggiustare il prima possibile")?

Separare con () rende molto più semplice scremare e capire più tardi ...

    
risposta data 11.06.2013 - 21:40
fonte
2

Caso generale

In C #, la moltiplicazione e la divisione ha la precedenza sull'addizione e sulla sottrazione.

Ancora, StyleCop, uno strumento che applica uno stile comune alla base di codice con un ulteriore scopo di mitigare il rischio che i bug introdotti dal codice possano non essere abbastanza chiari, ha il regola SA1407 . Questa regola produrrà un avvertimento con un pezzo di codice come questo:

var a = 1 + 2 * 3;

È chiaro che il risultato è 7 e non 9 , ma ancora, StyleCop suggerisce di mettere le parentesi:

var a = 1 + (2 * 3);

Il tuo caso particolare

Nel tuo caso particolare, esiste una precedenza di AND rispetto a OR nella particolare lingua che usi.

Non è così che si comportano tutti i linguaggi. Molti altri trattano AND e OR allo stesso modo.

Come sviluppatore che lavora principalmente con C #, quando ho visto la tua domanda la prima volta e ho letto il pezzo di codice senza leggere quello che hai scritto prima, la mia prima tentazione era di commentare che le due espressioni non sono le stesse. Spero di aver letto tutta la domanda prima di commentare.

Questa particolarità e il rischio che alcuni sviluppatori possano credere che AND e OR abbiano la stessa priorità rende ancora più importante l'aggiunta di parentesi.

Non scrivere codice con un obiettivo per dimostrare che sei intelligente. Scrivi un codice con un obiettivo di leggibilità, anche da parte di persone che potrebbero non conoscere tutti gli aspetti della lingua.

    
risposta data 11.06.2013 - 21:44
fonte
1

Come tutti hanno detto, usa le parentesi ogni volta che rende l'espressione più leggibile. Tuttavia, se l'espressione è complicata, consiglierei di introdurre nuove funzioni per le sottoespressioni .

    
risposta data 12.06.2013 - 08:59
fonte
0

Or is it a sign that a developer needs to really sit down and become confident in the basics of their language?

Se si usa rigorosamente lingua in singolare, forse. Ora prendi tutte le lingue che conosci, dai vecchi ai più moderni, dalla compilazione allo scripting in SQL alla tua DSL che hai inventato il mese scorso.

Ricordi le esatte regole di precedenza per ciascuna di queste lingue, senza guardare?

    
risposta data 11.06.2013 - 21:13
fonte
0

"Devo usare parentesi in istruzioni logiche anche dove non necessario."

Sì, perché due persone le troveranno utili:

  • Il prossimo programmatore, a conoscenza, competenza o stile potrebbe essere diverso

  • Il futuro te che ritorni a questo codice in un secondo momento!

risposta data 16.06.2013 - 16:20
fonte
-1

I condizionali complessi sono "algebra booleana", che scrivi in un certo modo che, beh, lo fanno sembrare esattamente come l'algebra, e dovresti usare parens per algebra , non lo farebbe voi?

Le regole veramente utili sono quelle di negazione:

!(A || B) <=> !A && !B
!(A && B) <=> !A || !B

Oppure, in un formato poco chiaro:

!(A + B) <=> !A * !B
!(A * B) <=> !A + !B

che è veramente chiaramente solo algebra quando scritto come:

-1*(A + B) = -A + -B
-1*(A * B) = -A * -B

Ma possiamo anche applicare il pensiero per la semplificazione e l'espansione algebrica:

(A && B) || (C && D) => 
((A && B) || C) && ((A && B) || D) => 
(AC && BC) && (AD && BD) =>
AC && BC && AD && BD

anche se nel codice devi scrivere:

(A||C) && (B||C) && (A||D) && (B||D)

o, in un formato poco chiaro:

(A + B) * (C + D) => 
((A + B) * C) + ((A + B) * D) => 
(AC + BC) + (AD + BD) =>
AC + BC + AD + BD

Fondamentalmente, un condizionale è ancora solo un'espressione algebrica e, usando chiaramente le parentesi, puoi applicare più facilmente le varie regole algebriche che già conosci nell'espressione, incluso il vecchio concetto di "semplificare o espandere questa formula".

    
risposta data 12.06.2013 - 01:18
fonte
-1

Userò la parentesi anche se è facoltativa, perché perché aiuta a capire meglio per tutti, per chi scrive il codice oltre a quello pronto a vedere quel codice. Nel tuo caso, anche gli operatori booleani hanno la precedenza che potrebbe funzionare bene all'inizio, ma non possiamo dire che ti aiuterà in ogni caso. quindi preferisco la parentesi dell'utente in qualsiasi condizione che lo richieda o facoltativamente.

    
risposta data 14.06.2013 - 04:10
fonte
-1

Sì. Dovresti usare in ogni caso quando ritieni che il tuo codice sarà più chiaro. Ricorda che il tuo codice dovrebbe essere abbastanza chiaro in modo che altri possano capire senza leggere i tuoi commenti all'interno del codice. Quindi è una buona pratica usare parentesi e parentesi graffe. Inoltre, tieni presente che ciò potrebbe dipendere dalla particolare pratica della tua azienda / squadra. Basta mantenere un approccio e non mescolare.

    
risposta data 27.06.2013 - 14:52
fonte

Leggi altre domande sui tag