L'operatore ternario è considerato dannoso? [chiuso]

77

Ad esempio, preferiresti questo one-liner

int median(int a, int b, int c) {
    return (a<b) ? (b<c) ? b : (a<c) ? c : a : (a<c) ? a : (b<c) ? c : b;
}

o una soluzione if / else che coinvolge più dichiarazioni di reso?

Quando ?: è appropriato e quando no? Dovrebbe essere insegnato o nascosto ai principianti?

    
posta FredOverflow 18.06.2013 - 19:56
fonte

25 risposte

229

Is the ternary operator evil?

No, è una benedizione.

When is ?: appropriate?

Quando è qualcosa di così semplice che non vuoi sprecare molte righe per.

and when is it not?

Quando la leggibilità e la chiarezza del codice ne risentono e il potenziale di errore per insufficiente attenzione aumenta, ad esempio, con molti operatori concatenati, proprio come nel tuo esempio.

La cartina tornasole è quando inizi a dubitare che il tuo codice sia facilmente leggibile e manutenibile a lungo termine. Quindi non farlo.

    
risposta data 20.08.2014 - 16:26
fonte
49

Penso che l'operatore ternario non verificato (vale a dire un'istruzione in cui viene usato una sola volta) va bene, ma se ne annidi più di uno, diventa un po 'difficile da leggere.

    
risposta data 21.12.2010 - 16:16
fonte
24

Quando è?: appropriato

  • Quando rende il tuo codice più conciso e leggibile.

e quando non lo è?

  • Quando rende il codice illeggibile.
  • Se lo fai solo per compiacere uno strumento di refactoring come ReSharper e non la persona che deve mantenere il codice

Se hai delle chiamate di logica o di funzione all'interno dell'espressione ternaria, rendi orribile da guardare.

    
risposta data 20.12.2010 - 18:12
fonte
21

Una differenza che (penso) che nessuno ha sottolineato è che if-else non può restituire un valore, mentre l'operatore ternario può.

Venendo da F #, a volte mi piace usare l'operatore ternario per simulare la corrispondenza del modello.

match val with
| A -> 1
| B -> 3
| _ -> 0

vs

return val == A ? 1 : 
       val == B ? 3 : 
       0;
    
risposta data 26.11.2012 - 07:15
fonte
12

Un esempio (IMHO) di un uso valido:

printf("Success in %d %s\n", nr_of_tries, (nr_of_tries == 1 ? "try" : "tries"));

Ciò si traduce in un codice più leggibile rispetto a due distinte dichiarazioni di stampa. Gli esempi nidificati dipendono da: (comprensibile? Sì: no)

    
risposta data 20.12.2010 - 20:07
fonte
5

Assolutamente non male. In realtà, è pure e if-then-else no.

Nei linguaggi funzionali come Haskell, F #, ML ecc., sono le dichiarazioni if-then-else che sono considerate malvagie.

La ragione di ciò è che ogni "azione" come un'istruzione imperativa if-then-else richiede di separare una dichiarazione di variabile dalla sua definizione e introduce stato alla tua funzione.

Ad esempio, nel seguente codice:

const var x = n % 3 == 1
    ? Parity.Even
    : Parity.Odd;

vs.

Parity x;
if (n % 3 == 1)
    x = Parity.Even;
else
    x = Parity.Odd;

Il primo ha due vantaggi oltre a essere più breve:

  1. x è una costante e quindi offre molte meno possibilità di introdurre bug e può potenzialmente essere ottimizzata in modi che il secondo non potrebbe mai essere.
  2. Il tipo è reso chiaro dall'espressione, quindi il compilatore può facilmente dedurre che x deve essere di tipo Parity .

Confusamente, nei linguaggi funzionali, l'operatore ternario viene spesso chiamato if-then-else. In Haskell, potresti dire x = if n mod 3 == 1 then Odd else Even .

    
risposta data 21.12.2010 - 15:56
fonte
5

Quell'espressione particolare mi fa male agli occhi; Sbatterei uno sviluppatore del mio team che lo usava perché non è possibile.

Gli operatori ternari non sono cattivi se usati bene. Non devono nemmeno essere linee singole; Una lunga formattazione può essere molto chiara e facile da capire:

return
      ( 'a' == $s ) ? 1
    : ( 'b' == $s ) ? 2
    : ( 'c' == $s ) ? 3
    :                 4;

Mi piace meglio della catena if / then / else equivalente:

if ( 'a' == $s ) {
    $retval = 1;
}
elsif ( 'b' == $s ) {
    $retval = 2;
}
elsif ( 'c' == $s ) {
    $retval = 3;
}
else {
    $retval = 4;
}

return $retval;

Le riformatterò in:

if    ( 'a' == $s ) { $retval = 1; }
elsif ( 'b' == $s ) { $retval = 2; }
elsif ( 'c' == $s ) { $retval = 3; }
else                { $retval = 4; }

return $retval;

se le condizioni e i compiti consentono un facile allineamento. Comunque preferisco la versione ternaria perché è più corta e non ha tanto rumore intorno alle condizioni e ai compiti.

    
risposta data 22.12.2010 - 07:51
fonte
3

ReSharper in VS.NET a volte suggerisce di sostituire if...else con l'operatore ?: .

Sembra che ReSharper suggerisca solo se le condizioni / blocchi sono al di sotto di un certo livello di complessità, altrimenti si attacca con if...else .

    
risposta data 20.12.2010 - 21:58
fonte
2

Questo può essere riformattato per essere bello come la combinazione if / else:

int median(int a, int b, int c)
{
    return
        (a<b)
        ?
            (b<c)
            ? b
            :
                (a<c)
                ? c
                : a
        :
            (a<c)
            ? a
            :
                (b<c)
                ? c
                : b;
}

Ma il problema è che non sono davvero sicuro se ho il diritto all'indentazione di rappresentare ciò che accadrà realmente. : -)

    
risposta data 20.12.2010 - 23:07
fonte
2

Lontano dall'essere cattivo, l'operatore ternario è una manna dal cielo.

  • È molto utile quando vuoi prendere una decisione in un'espressione annidata . L'esempio classico è una chiamata di funzione:

    printf("I see %d evil construct%s in this program\n", n, n == 1 ? "" : "s");
    
  • Nel tuo particolare esempio, il ternario è quasi gratuito, poiché è l'espressione di livello superiore sotto return . Puoi portare il condizionale a livello di istruzione senza duplicare altro che la parola chiave return .

NB. Niente potrà mai rendere quel particolare algoritmo per la mediana di facile lettura.

    
risposta data 21.12.2010 - 03:55
fonte
2
  1. Argomenti "malvagi" a parte, nella mia esperienza ho trovato un'alta correlazione tra l'uso dell'operatore ternario da parte di un programmatore e la possibilità che la sua intera base di codice sia difficile da leggere, seguire e mantenere (se non completamente privi di documenti). Se un programmatore è più interessato a salvare poche righe di 1-2 caratteri rispetto a qualcuno che è in grado di capire il suo codice, allora qualsiasi minima confusione che comprende un'affermazione ternaria è solitamente la punta dell'iceberg.

  2. Gli operatori ternari attraggono numeri magici come s ** t attira le mosche.

Se stavo cercando una libreria Open Source per risolvere un problema particolare, e ho visto un codice come gli operatori ternari del poster originale in un candidato per la libreria, le campane di avvertimento si sarebbero sparse nella mia testa e io avrei iniziato considerando di passare a qualche altro progetto da cui prendere a prestito.

    
risposta data 21.12.2010 - 18:12
fonte
2

Ecco un esempio di quando è evil:

oldValue = newValue >= 0 ? newValue : oldValue;

È confuso e dispendioso. Il compilatore potrebbe ottimizzare la seconda espressione (oldValue = oldValue), ma perché il coder ha fatto questo in primo luogo?

Another doozy:

thingie = otherThingie != null ? otherThingie : null;

Alcune persone non sono pensate per essere programmatori ...

Greg dice che l'equivalente se l'istruzione è "rumorosa". È se lo scrivi rumorosamente. Ma lo stesso se può essere scritto come:

if ('a' == $s) return 1;
if ('b' == $s) return 2;
if ('c' == $s) return 3;
return 4;

Che non è più rumoroso del ternario. Mi chiedo se le scorciatoie ternarie; vengono valutate tutte le espressioni?

    
risposta data 26.01.2011 - 00:21
fonte
2

Male? Guarda, sono solo diversi.

if è una dichiarazione. (test ? a : b) è un'espressione. Non sono la stessa cosa.

Esistono espressioni per esprimere valori. Esistono dichiarazioni per eseguire azioni. Le espressioni possono apparire all'interno delle istruzioni, ma non viceversa. Quindi puoi usare espressioni ternarie all'interno di altre espressioni, come per i termini di una sommatoria, o per gli argomenti di un metodo, e così via. Non devi , ma puoi puoi se vuoi . Non c'è niente di sbagliato in questo. Alcune persone potrebbero dire che è male, ma questa è la loro opinione.

Un valore di un'espressione ternaria è che ti permette di gestire sia casi veri che falsi. if dichiarazioni no.

Se sei preoccupato per la leggibilità, puoi formattarli in modo leggibile.

In qualche modo il "male" si insinuava nel vocabolario della programmazione. Mi piacerebbe sapere chi l'ha fatto prima. (In realtà, ho un sospetto - è al MIT.) Preferirei che avessimo ragioni obiettive per i giudizi di valore in questo campo, non solo per il gusto e la denominazione delle persone.

    
risposta data 26.01.2011 - 02:17
fonte
1

Ha un posto. Ho lavorato in molte aziende in cui i livelli di abilità degli sviluppatori vanno da terribili a mago. Poiché il codice deve essere mantenuto, e io non ci sarò per sempre, cerco di scrivere cose in modo che appaia come se fosse lì (senza guardare i commenti con le mie iniziali, è estremamente raro che tu sia in grado di guarda il codice su cui ho lavorato per vedere dove ho apportato le modifiche) e che qualcuno con meno capacità di me può mantenerlo.

Mentre l'operatore ternario ha un aspetto nitz-fico e molto interessante, la mia esperienza è che la linea di codice sarà impossibile da mantenere. Al mio attuale datore di lavoro, abbiamo prodotti che sono stati in vendita per quasi 20 anni. Non userei quell'esempio ovunque.

    
risposta data 20.12.2010 - 17:54
fonte
1

Non penso che l'operatore ternario sia malvagio.

Ecco un trucco che mi ha lasciato perplesso, però. Sono stato un programmatore C per molti (10+) e alla fine degli anni '90 mi sono trasferito nella programmazione di applicazioni basate sul web. Come programmatore web, ho presto incontrato PHP che ha anche un operatore ternario. Ho avuto un bug in un programma PHP che ho finalmente tracciato su una riga di codice con un operatore ternario annidato. Si scopre che l'operatore ternario di PHP si associava da sinistra a destra ma l'operatore ternario C (a cui ero abituato) associava da destra a sinistra.

    
risposta data 20.12.2010 - 18:47
fonte
1

Tutto ciò che rende il tuo codice più brutto è malvagio.

Se usi ternario per rendere il tuo codice più pulito, sicuramente usalo. A volte, come in PHP, è bello fare sostituzioni in linea, ad es.

"Hello ".($Male?"Mr":"Ms")." $Name

Questo salva poche righe, ed è abbastanza chiaro, ma il tuo esempio ha bisogno di una formattazione almeno migliore per essere chiaro, e il ternario non è veramente buono per la multi-linea, quindi potresti usare anche se / else.

    
risposta data 21.12.2010 - 03:38
fonte
1

Posso dirlo? Non riesco a trovare questa particolare applicazione dell'operazione ternaria evil :

  1. l'operazione che esegue è piuttosto banale, e una volta che si è passati ad esso una volta è quasi impossibile che alcuni bug vengano fuori;
  2. quello che fa è chiaramente indicato nel nome della funzione;
  3. prendere > 1 linea per qualcosa di così ovvio e così chiaramente non sarebbe migliorato in futuro (a meno che un algoritmo mediano magico non sia mai stato scoperto fino ad ora).

Per favore abbi pietà, la mia reputazione è già piuttosto penosa.

    
risposta data 21.12.2010 - 16:04
fonte
1

Vittoria più grande: dimostra che esiste un unico obiettivo di azione.

if ( $is_whatever )
    $foo = 'A';
else
    $foo = 'B';

Ci sono due percorsi di codice che è possibile seguire e il lettore deve leggere attentamente per vedere quali due variabili vengono impostate. In questo caso, è solo una variabile, ma il lettore ha più da leggere per capirlo. Dopotutto, avrebbe potuto essere questo:

if ( $is_whatever )
    $foo = 'A';
else
    $bar = 'B';

Con l'operatore ternario, è chiaro che è stata impostata una sola variabile.

$foo = $is_whatever ? 'A' : 'B';

Al livello più basso, è il principio DRY (Do not Repeat Yourself) al suo livello più basilare. Se puoi specificare $foo solo una volta, fallo.

    
risposta data 26.11.2012 - 16:46
fonte
0

Se ... allora ... else tende a enfatizzare la condizione e quindi de-enfatizzare le operazioni eseguite condizionatamente.

l'operatore ternario è il contrario, tende a nascondere la condizione ed è quindi utile quando l'operazione eseguita è più importante della condizione stessa.

C'è un piccolo inconveniente tecnico, in alcune lingue, che non sono abbastanza intercambiabili a causa di una dichiarazione e di un'espressione, ad es. inizializzazione condizionale in C ++

    
risposta data 20.12.2010 - 17:58
fonte
0

When is appropriate, and when is it not?

Penso che quando si sviluppa per un gruppo omogeneo di persone, non ci sono problemi, ma quando si ha a che fare con persone che gestiscono livelli diversi, questo tipo di onelineri introduce solo un ulteriore livello di complessità nel codice. Quindi, la mia politica in materia è: codice chiaro e non spiegare piuttosto che codice breve e spiegare 123123 volte.

Should it be taught to or hidden from beginners?

Non dovrei essere insegnato ai principianti, preferisco piuttosto che lo capiscano quando emerge il bisogno, quindi sarà usato solo quando necessario e non ogni volta che avrai bisogno di un if.

    
risposta data 20.12.2010 - 23:25
fonte
0

IMO, l'operatore stesso non è malvagio, ma la sintassi utilizzata in C (e C ++) è eccessivamente concisa. IMO, Algol 60 ha fatto meglio, quindi qualcosa del genere:

A = x == y ? B : C;

sarebbe più simile a questo (ma attenendosi alla sintassi simile a C in generale):

A = if (x==y) B else C;

Anche con questo, una nidificazione eccessivamente profonda può portare a problemi di leggibilità, ma almeno A) chiunque abbia programmato del tutto può capirlo in modo semplice, e B) le persone che lo capiscono possono gestire una nidificazione molto più profonda abbastanza facilmente . OTOH, noterei anche che in LISP (per esempio) un cond è praticamente un'affermazione ternaria - non un insieme di istruzioni, ma una singola espressione produce un valore (quindi di nuovo, la maggior parte di LISP è come che ...)

    
risposta data 25.01.2011 - 21:12
fonte
0

Un negozio che regolarmente scrive metodi da 600-1200 righe non dovrebbe dirmi che un ternario è "difficile da capire". Qualsiasi negozio che regolarmente consente a cinque condizioni di valutare un ramo di codice non dovrebbe dirmi che le condizioni concretamente riassunte in un ternario sono "difficili da leggere".

    
risposta data 11.03.2011 - 17:13
fonte
0

Quando è?: appropriato, e quando non lo è?

  • Se non ottieni un guadagno in termini di prestazioni, non usarlo; influisce sulla leggibilità del tuo codice.
  • Usalo una volta e non annidarlo.
  • È più difficile eseguire il debug.

Dovrebbe essere insegnato o nascosto ai principianti?

Non importa, ma non dovrebbe essere nascosto intenzionalmente in quanto non è troppo complesso per un "principiante" da imparare.

    
risposta data 23.09.2015 - 22:11
fonte
-2

Nel tuo esempio:

def median(a, b, c):
    if a < b < c: return b
    if a < c < b: return c
    if b < a < c: return a
    if b < c < a: return c
    if c < a < b: return a
    if c < b < a: return b

è molto semplice da leggere e ovvio. La variabile tra il < < è il valore di ritorno.

Aggiornamento

stesso, ma meno righe di codice. Ancora semplice, penso.

def median(a, b, c):
    if b<a<c or c<a<b: return a
    if a<b<c or c<b<a: return b
    if a<c<b or b<c<a: return c
    
risposta data 26.01.2011 - 01:50
fonte
-2

È anche necessario per const

const int nLegs  = isChicken ? 2: 4 ;
    
risposta data 11.03.2011 - 17:40
fonte

Leggi altre domande sui tag