it-swarm.it

Operatore ternario considerato dannoso?

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 non lo è? Dovrebbe essere insegnato o nascosto ai principianti?

82
fredoverflow

L'operatore ternario è malvagio?

No è una benedizione.

Quando è?: Appropriato?

Quando è qualcosa di così semplice per cui non vuoi sprecare molte linee.

e quando no?

Quando soffre la leggibilità e la chiarezza del codice e aumenta la possibilità di un errore a causa di un'attenzione insufficiente, ad esempio con molti operatori concatenati, proprio come nel tuo esempio.


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

236
user8685

Penso che l'operatore ternario innestato (cioè un'affermazione in cui viene usato solo una volta) va bene, ma se ne nidificano più di uno, diventa un po 'difficile da leggere.

50
mipadi

Quando è?: Appropriato

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

e quando no?

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

Se hai espressioni logiche o di funzione all'interno dell'espressione ternaria, stai rendendo orribile da guardare.

24
realworldcoder

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

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

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

vs

return val == A ? 1 : 
       val == B ? 3 : 
       0;
23
Benjol

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 ad avere 2 istruzioni di stampa distinte. Gli esempi nidificati dipendono: (comprensibile? Sì: no)

13
Henno Brandsma

Assolutamente non male. In realtà, è puro , e if-then-else non lo è.

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

Il motivo di ciò è che qualsiasi "azione" come un'istruzione if-then-else imperativa richiede di separare una dichiarazione di variabile dalla sua definizione e introduce stato nella 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 ad essere più breve:

  1. x è una costante e offre quindi molte meno possibilità di introdurre bug e può essere potenzialmente ottimizzato in modi che il secondo non potrebbe mai essere.
  2. Il tipo viene chiarito 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.

7
Rei Miyasaka

Quella particolare espressione mi fa male agli occhi; Vorrei sfuggire a qualsiasi sviluppatore del mio team che lo usasse perché non è realizzabile.

Gli operatori ternari non sono malvagi se usati bene. Non devono nemmeno essere linee singole; Un lungo ben formattato può essere molto chiaro e facile da capire:

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

Mi piace di più 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;

Li 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 le assegnazioni consentono un facile allineamento. Preferisco comunque la versione ternaria perché è più corta e non ha così tanto rumore attorno alle condizioni e ai compiti.

7
the Tin Man

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

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

3
Uwe Keim

Ecco un esempio di quando è male:

oldValue = newValue >= 0 ? newValue : oldValue;

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

Un altro doozy:

thingie = otherThingie != null ? otherThingie : null;

Alcune persone non sono pensate per essere programmatori ...

Greg afferma che l'equivalente if è "rumoroso". Lo è 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?

2
hapybrian

Lungi dall'essere malvagio, l'operatore ternario è una manna dal cielo.

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

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

N.B. Nulla renderà mai quel particolare algoritmo per la mediana di facile lettura.

2
Norman Ramsey
  1. Argomenti "malvagi" a parte, nella mia esperienza ho trovato un'alta correlazione tra l'uso da parte di un programmatore dell'operatore ternario e la probabilità che l'intera sua base di codice sia difficile da leggere, seguire e mantenere (se non del tutto priva di documenti). Se un programmatore è più interessato a salvare alcune righe di 1-2 caratteri rispetto a qualcuno che è in grado di capire il proprio codice, allora qualsiasi confusione minore che capisca un'affermazione ternaria è di solito la punta dell'iceberg.

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

Se stavo cercando una biblioteca Open Source per risolvere un problema particolare, e vedessi codice come gli operatori ternari del poster originale in un candidato per detta biblioteca, le campane di avvertimento inizierebbero a suonare nella mia testa e inizierei a pensare di andare avanti a qualche altro progetto da cui prendere in prestito.

2
user8865

Il male? Guarda, sono solo diversi.

if è un'istruzione. (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 è possibile utilizzare espressioni ternarie all'interno di altre espressioni, ad esempio per i termini in un riepilogo o per gli argomenti di un metodo e così via. Non devi, ma puoi se vuoi. Non c'è niente di sbagliato in questo. Alcune persone potrebbero dire che è malvagio, ma questa è la loro opinione.

Un valore di un'espressione ternaria è che ti fa gestire sia i casi veri che falsi. if istruzioni no.

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

In qualche modo "male" si insinuò nel vocabolario della programmazione. Mi piacerebbe sapere chi l'ha lasciato cadere per primo. (In realtà, ho un sospetto - è al MIT.) Preferirei che avessimo ragioni oggettive per giudizi di valore in questo campo, non solo per il gusto e la vocazione delle persone.

2
Mike Dunlavey

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 di avere il rientro giusto per rappresentare ciò che accadrà effettivamente. :-)

2
Zan Lynx

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

  1. l'operazione che esegue è piuttosto banale, e una volta che l'avete superata una volta è quasi impossibile che emergano alcuni bug;
  2. ciò che fa è chiaramente indicato nel nome della funzione;
  3. prendendo> 1 linea per qualcosa di così ovvio e che così chiaramente non sarebbe migliorato in futuro (a meno che un algoritmo mediano magico non sia vissuto fino ad ora inosservato).

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

1
cbrandolino

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

Se usi ternary per rendere il tuo codice più pulito, assicurati di usarlo. A volte come in php è bello fare sostituzioni in linea, ad es.

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

Ciò consente di risparmiare alcune righe, ed è abbastanza chiaro, ma il tuo esempio ha bisogno di una formattazione migliore per essere chiaro, e ternario non è davvero buono per la multi-linea, quindi potresti anche usare if/else.

1
user11134

La più grande vittoria: dimostrare che esiste un solo obiettivo di azione.

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

Esistono 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 solo una variabile.

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

Al livello più basso, è il principio DRY (Don't Repeat Yourself) nella sua forma più elementare. Se puoi specificare $foo solo una volta, fallo.

1
Andy Lester

Ha un posto. Ho lavorato in molte aziende in cui i livelli di abilità degli sviluppatori vanno dal terribile al mago. Dato che il codice deve essere mantenuto, e non ci sarò per sempre, provo a scrivere cose in modo che sembri che vi appartenga (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 abilità di me stesso può mantenerlo.

Mentre l'operatore ternario sembra nitziffic e molto bello, la mia esperienza è che la linea di codice sarà quasi impossibile da mantenere. Al mio attuale datore di lavoro, abbiamo prodotti che spediscono da quasi 20 anni. Non userei questo esempio da nessuna parte.

1
Tangurena

Non penso che l'operatore ternario sia malvagio.

Ecco un gotcha che mi ha lasciato perplesso, però. Sono stato un programmatore C per molti (10+) e alla fine degli anni '90 sono passato alla programmazione di applicazioni basate sul web. Come programmatore web, mi sono imbattuto presto in PHP che ha anche un operatore ternario. Ho avuto un bug in un PHP che ho finalmente rintracciato in una riga di codice con un operatore ternario nidificato. Si scopre che l'operatore ternario PHP associato associato da sinistra a destra ma l'operatore ternario C (a cui ero abituato) associa da destra a sinistra.

1
leed25d

Quando è appropriato e quando non lo è?

Penso che quando si sviluppa per un gruppo omogeneo di persone, non vi è alcun problema, ma quando si ha a che fare con persone che gestiscono livelli diversi, questo tipo di oneliner 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.

Dovrebbe essere insegnato o nascosto ai principianti?

Non dovrei insegnare ai principianti, piuttosto preferisco che capiscano quando emerge la necessità, quindi sarà usato solo quando necessario e non tutte le volte che hai bisogno di un se.

0
guiman

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

0
Axeman

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

A = x == y ? B : C;

apparirebbe più simile a questo (ma attenendosi alla sintassi di tipo C in generale):

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

Anche con ciò, un annidamento eccessivamente profondo può portare a problemi di leggibilità, ma almeno A) chiunque abbia finito di programmare può capirne uno semplice, e B) le persone che lo capiscono possono gestire un annidamento considerevolmente più profondo abbastanza facilmente. OTOH, vorrei anche notare che in LISP (per esempio) un cond è praticamente come un'istruzione ternaria - non un insieme di istruzioni, ma una singola espressione produce un valore (poi di nuovo, la maggior parte di LISP è così ...)

0
Jerry Coffin

Quando è?: Appropriato e quando non lo è?

  • Se non ottieni un guadagno in termini di prestazioni, non utilizzarlo; influisce sulla leggibilità del tuo codice.
  • Usalo una volta e non nidificarlo.
  • È 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 essere appreso da un "principiante".

0
Amir Rezaei

Se ... allora ... altrimenti tende a enfatizzare la condizione e quindi a de-enfatizzare le operazioni che sono condotte condizionatamente.

l'operatore ternario è l'opposto, tende a nascondere la condizione ed è quindi utile quando l'operazione in corso è più importante della condizione stessa.

C'è un piccolo inconveniente tecnico, in alcune lingue, che non sono abbastanza intercambiabili a causa del fatto che uno è un'istruzione e uno un'espressione, ad es. inizializzazione condizionale dei cons in C++

0
jk.