Ternario o non ternario? [chiuso]


186

Personalmente sono un sostenitore dell'operatore ternario: ()? :; Mi rendo conto che ha il suo posto, ma mi sono imbattuto in molti programmatori che sono completamente contrari al suo utilizzo e alcuni che lo usano troppo spesso.

Quali sono i tuoi sentimenti? Quale codice interessante hai visto usarlo?


22
Un sostenitore di qualcosa è una persona che sostiene quella cosa.
Doug McClean,

8
Usalo quando è chiaro, evitalo quando confonde. È una chiamata di giudizio. Può rendere il codice più leggibile, ma solo per espressioni semplici. Cercare di usarlo sempre è una minaccia tanto quanto evitarlo incessantemente.
Abele,

3
In realtà, è l'operatore condizionale. Una domanda quasi duplicata è stackoverflow.com/questions/725973/… .
Daniel Daranas,

Qualche volta stavo usando x = x if x else yma poi l' ho chiesto e realizzato con altri aiuti che si riduce davvero a x = xo y ( stackoverflow.com/questions/18199381/self-referencing-ternary/… )
Scruffy

4
Domande come queste non devono essere considerate non costruttive.
Ungeheuer,

Risposte:


243

Usalo solo per espressioni semplici :

int a = (b > 10) ? c : d;

Non concatenare o nidificare gli operatori ternari poiché è difficile da leggere e confondere:

int a = b > 10 ? c < 20 ? 50 : 80 : e == 2 ? 4 : 8;

Inoltre, quando si utilizza l'operatore ternario, considerare la formattazione del codice in modo da migliorare la leggibilità:

int a = (b > 10) ? some_value                 
                 : another_value;

81
Completamente d'accordo con le prime affermazioni ma totalmente in disaccordo con il tuo esempio di "migliore leggibilità". Se stai per multi-linea, perché non usare semplicemente un'istruzione if?
Joe Phillips,

3
solo perché if else è molto più prolisso per decisioni semplici: int a = 0; if (b> 10) a = some_value; altrimenti a = another_value; Cosa preferisci?
marcospereira,

44
@ d03boy: Perché if-statement è proprio questo, un'affermazione e non farà quando tutto ciò che vuoi è un'espressione.
falstro,

2
@roe in alcune lingue se è espressione (ad esempio in Scala), quindi val x = if(true) 0 else 1è perfettamente legale
om-nom-nom

5
@ om-nom-nom case in point, che lo renderebbe un'espressione if, piuttosto che un'istruzione if, ed è essenzialmente la stessa cosa dell'operatore?: -.
falstro,

141

Rende il debug leggermente più difficile poiché non è possibile posizionare punti di interruzione su ciascuna delle espressioni secondarie. Lo uso raramente.


44
Questo è il miglior argomento contro l'operatore ternario che abbia mai sentito. Non compro l'argomento "non leggibile" (mi sembra che le persone siano troppo pigre per abituarsi), ma in realtà ha sostanza.
EpsilonVector

80

Li adoro, soprattutto in linguaggi sicuri.

Non vedo come questo:

int count = (condition) ? 1 : 0;

è più difficile di così:

int count;

if (condition)
{
  count = 1;
} 
else
{
  count = 0;
}

modificare -

Direi che gli operatori ternari rendono tutto meno complesso e più pulito dell'alternativa.


5
L'inizializzazione ternaria è ancora più utile in D o C ++ quando la variabile è costante. ad es. const int count = ...;
codice deft

Bene, stai in qualche modo travisando if/elsecon le parentesi graffe non necessarie lì.
Bobobobo,

1
Inoltre, in questo caso, se conditionè bool si può solo fare int count = condition;
bobobobo

1
@bobobobo questo if/elsecon parentesi graffe è come la maggior parte dei programmatori riscriverà il ternario ..
Andre Figueiredo

1
@bobobobo if / else w / o braces sta solo chiedendo problemi. È fin troppo facile per qualcuno aggiungere una linea, ma dimentica che ci vorranno delle parentesi graffe per fare ciò che si aspettano (esegui la linea aggiuntiva come parte di un blocco): stackoverflow.com/a/381274/377225
George Marian

43

Incatenato con cui sto bene - nidificato, non tanto.

Tendo ad usarli di più in C semplicemente b / c sono un'istruzione if che ha valore, quindi riduce le ripetizioni o le variabili non necessarie:

x = (y < 100) ? "dog" :
    (y < 150) ? "cat" :
    (y < 300) ? "bar" : "baz";

piuttosto che

     if (y < 100) { x = "dog"; } 
else if (y < 150) { x = "cat"; }
else if (y < 300) { x = "bar"; } 
else              { x = "baz"; }

In incarichi come questo, trovo che sia meno refactoring e più chiaro.

D'altra parte, quando lavoro nel rubino, ho più probabilità di usarlo if...else...endperché è anche un'espressione.

x =   if (y < 100) then "dog"
    elif (y < 150) then "cat"
    elif (y < 300) then "bar"
    else                "baz"
    end

(anche se, devo ammetterlo, per qualcosa di così semplice, potrei comunque usare l'operatore ternario).


2
Mi piace il tuo primo esempio - non avevo mai pensato di concatenarli in quel modo prima. Grazie per la condivisione. =)
Erik Forbes,

5
+1 Di recente ho iniziato a farlo. In realtà lo faccio anche per sostituire le istruzioni switch.
Davy8,

1
Ottimo esempio @rampion.
illuminerà l'

39

L' ?:operatore ternario è semplicemente un equivalente funzionale del ifcostrutto procedurale . Quindi, purché non si utilizzino ?:espressioni nidificate , qui si applicano gli argomenti a favore / contro la rappresentazione funzionale di qualsiasi operazione. Ma l'annidamento delle operazioni ternarie può comportare un codice decisamente confuso (esercizio per il lettore: prova a scrivere un parser che gestirà i condizionali ternari annidati e ne apprezzerai la complessità).

Ma ci sono molte situazioni in cui un uso prudente ?:dell'operatore può risultare in un codice che in realtà è più facile da leggere rispetto al resto. Per esempio:

int compareTo(Object object) {
    if((isLessThan(object) && reverseOrder) || (isGreaterThan(object) && !reverseOrder)) {
       return 1;
    if((isLessThan(object) && !reverseOrder) || (isGreaterThan(object) && reverseOrder)) {
       return -1;
    else
      return 0;              
}

Ora confrontalo con questo:

int compareTo(Object object) {
    if(isLessThan(object))
        return reverseOrder ? 1 : -1;         
    else(isGreaterThan(object))
        return reverseOrder ? -1 : 1;
    else        
       return 0;              
}

Dato che il codice è più compatto, c'è meno rumore sintattico e usando l'operatore ternario con giudizio (cioè solo in relazione alla proprietà reverseOrder ) il risultato finale non è particolarmente conciso.


continuerei a raccomandare di usare i riconoscimenti su ogni costruzione if / then / else che non è ternaria, quindi il tuo secondo esempio manca di alcuni imho.
Kris,

Sì, è funzionale. È come una piccola funzione che ha un singolo argomento booleano e restituisce qualsiasi tipo tu voglia! In realtà un operatore pulito.
Bobobobo,

24

È una questione di stile, davvero; le regole inconsce che tendo a seguire sono:

  • Valuta solo 1 espressione - quindi foo = (bar > baz) ? true : false, ma NONfoo = (bar > baz && lotto && someArray.Contains(someValue)) ? true : false
  • Se lo sto usando per la logica di visualizzazione, ad es <%= (foo) ? "Yes" : "No" %>
  • Usalo davvero solo per il compito; mai flusso logico (quindi mai (foo) ? FooIsTrue(foo) : FooIsALie(foo)) La logica del flusso in ternario è essa stessa una bugia, ignora quell'ultimo punto.

Mi piace perché è conciso ed elegante per semplici operazioni di assegnazione.


buone linee guida e buoni esempi!
nickf

Penso che la maggior parte dei langauges non ti permetta di usarlo per la logica del flusso, quindi non puoi farlo (pippo)? Vero (pippo): Falso (pippo); a meno che non fosse un incarico.
Henry B,

Oops, sì hai ragione, mia cattiva.
Keith Williams,

21
I tuoi primi due esempi sono davvero pessimi. I risultati dei confronti sono già valori booleani, quindi i tuoi operatori ternari sono inutili e complicano solo il codice.
Trillian,

1
@Trillian +1 Sì, avrebbe dovuto assegnare un compito diverso. foo = (bar > baz);è molto più semplice
Eric

18

Come tante domande d'opinione, la risposta è inevitabilmente: dipende

Per qualcosa come:

return x ? "Yes" : "No";

Penso che sia molto più conciso (e più veloce per me da analizzare) di:

if (x) {
    return "Yes";
} else {
    return "No";
}

Ora se la tua espressione condizionale è complessa, l'operazione ternaria non è una buona scelta. Qualcosa di simile a:

x && y && z >= 10 && s.Length == 0 || !foo

non è un buon candidato per l'operatore ternario.

A parte questo, se sei un programmatore C, GCC in realtà ha un'estensione che ti consente di escludere la porzione if-true del ternario, in questo modo:

/* 'y' is a char * */
const char *x = y ? : "Not set";

Che imposterà xa ysupporre di yno NULL. Roba buona.


Risolto un problema relativo alla sintassi e alla grammatica, Sean :-) Manca y dall'ultimo bit di codice e "assegna x a y" significa "y = x", quindi chgd su "imposta x su y".
paxdiablo,

@Pax: grazie! Ho annullato la modifica della sintassi poiché stavo cercando di sottolineare che con le estensioni GCC non è necessaria la parte if-true del ternario.
Sean Bright,

Spiacente, non ho visto quel paragrafo. Non so che sono d'accordo con questo genere di cose, poiché consente alle persone di scrivere codice che non verrà compilato con un compilatore standard ISO. Tuttavia, quando GCC è l'ultimo uomo in piedi, non importa :-)
paxdiablo,

È voodoo, sicuramente ... E chi non usa GCC? : D
Sean Bright,

14

Nella mia mente, ha senso usare l'operatore ternario solo nei casi in cui è necessaria un'espressione.

In altri casi, sembra che l'operatore ternario diminuisca la chiarezza.


il problema è che è il 99% della lingua, un'espressione può essere sostituita da una funzione ... e evitando che l'operatore ternario preferisca persino quella soluzione.
PierreBdR,

11

Per la misura della complessità ciclomatica , l'uso di ifdichiarazioni o l'operatore ternario sono equivalenti. Quindi, con questa misura, la risposta è no , la complessità sarebbe esattamente la stessa di prima.

Con altre misure come la leggibilità, la manutenibilità e il DRY (Don't Repeat-Yourself), entrambe le scelte possono rivelarsi migliori dell'altra.


10

Lo uso abbastanza spesso in luoghi in cui sono costretto a lavorare in un costruttore - ad esempio i nuovi costrutti .NET 3.5 LINQ to XML - per definire valori predefiniti quando un parametro facoltativo è nullo.

Esempio contrastato:

var e = new XElement("Something",
    param == null ? new XElement("Value", "Default")
                  : new XElement("Value", param.ToString())
);

o (grazie asterite)

var e = new XElement("Something",
    new XElement("Value",
        param == null ? "Default"
                      : param.ToString()
    )
);

Non importa se usi l'operatore ternario o meno, assicurarti che il tuo codice sia leggibile è la cosa importante. Qualsiasi costrutto può essere reso illeggibile.


Oppure ... var e = new XElement ("Something", new XElement ("value", param == null? "Default": param.toString ()));
asterite,

2
Mi piace che lo stai formattando per essere leggibile, quindi molti non lo fanno.
Bruceatk,

A che serve il codice sorgente leggibile dall'uomo se non è leggibile dall'uomo? =)
Erik Forbes,

9

Uso l'operatore ternario ogni volta che posso, a meno che non renda il codice estremamente difficile da leggere, ma di solito è solo un'indicazione che il mio codice potrebbe usare un piccolo refactoring.

Mi sconcerta sempre il modo in cui alcune persone pensano che l'operatore ternario sia una funzione "nascosta" o sia in qualche modo misteriosa. È una delle prime cose che ho imparato quando ho iniziato a programmare in C e non credo che diminuisca affatto la leggibilità. È una parte naturale della lingua.


1
Sono completamente d'accordo. Non c'è nulla di nascosto o complicato al riguardo.
mmattax,

2
Può causare problemi di leggibilità, soprattutto se nidificati.
David Thornley,

Penso che " estremamente difficile da leggere" sia un po 'troppo permissivo, ma nel complesso sono d'accordo con te. Non c'è nulla di difficile o mistico al riguardo.
EpsilonVector

7

Sono d'accordo con jmulder: non dovrebbe essere usato al posto di a if, ma ha il suo posto per espressione di ritorno o dentro un'espressione:

echo "Result: " + n + " meter" + (n != 1 ? "s" : "");
return a == null ? "null" : a;

Il primo è solo un esempio, dovrebbe essere usato un supporto i18n migliore del plurale!


Il primo ternario non è corretto - hai un: dove il? dovrebbe andare: (n! = 1 ? "s": "")
Erik Forbes,

Sì, grazie per averlo sottolineato! Fisso.
PhiLho,

7

(Hack del giorno)

#define IF(x) x ?
#define ELSE :

Quindi puoi fare if-then-else come espressione:

int b = IF(condition1)    res1
        ELSE IF(condition2)  res2
        ELSE IF(conditions3) res3
        ELSE res4;

questo non risponde alla domanda
Bruno Alexandre Rosa

6

Se stai usando l'operatore ternario per un semplice incarico condizionale, penso che vada bene. L'ho visto (ab) usato per controllare il flusso del programma senza nemmeno fare un compito, e penso che dovrebbe essere evitato. Utilizzare un'istruzione if in questi casi.


5

Penso che l'operatore ternario dovrebbe essere usato quando necessario. È ovviamente una scelta molto soggettiva, ma trovo che un'espressione semplice (specialmente come espressione di ritorno) sia molto più chiara di un test completo. Esempio in C / C ++:

return (a>0)?a:0;

Rispetto a:

if(a>0) return a;
else return 0;

Hai anche il caso in cui la soluzione è tra l'operatore ternario e la creazione di una funzione. Ad esempio in Python:

l = [ i if i > 0 else 0 for i in lst ]

L'alternativa è:

def cap(value):
    if value > 0:
        return value
    return 0
l = [ cap(i) for i in lst ]

È sufficiente che in Python (come esempio), un tale linguaggio possa essere visto regolarmente:

l = [ ((i>0 and [i]) or [0])[0] for i in lst ]

questa linea usa le proprietà degli operatori logici in Python: sono pigri e restituiscono l'ultimo valore calcolato se è uguale allo stato finale.


3
Quest'ultima linea mi fa male al cervello ...
Erik Forbes,

5

Mi piacciono. Non so perché, ma mi sento molto bene quando uso l'espressione ternaria.


5

Ho visto bestie del genere (in realtà era molto peggio dato che era Validata e controllato anche mese e giorno, ma non potevo preoccuparmi di cercare di ricordare tutto):

isLeapYear =
    ((yyyy % 400) == 0)
    ? 1
    : ((yyyy % 100) == 0)
        ? 0
        : ((yyyy % 4) == 0)
            ? 1
            : 0;

dove, chiaramente, una serie di istruzioni if ​​sarebbe stata migliore (anche se questa è ancora migliore della versione macro che ho visto una volta).

Non mi dispiace per le piccole cose come:

reportedAge = (isFemale && (Age >= 21)) ? 21 + (Age - 21) / 3 : Age;

o anche cose leggermente difficili come:

printf ("Deleted %d file%s\n", n, (n == 1) ? "" : "s");

Come si può dire una serie di isolanti se le dichiarazioni sarebbero più leggibili? Ho letto il tuo "bestia" che bene . reportedAgeè l'esempio che richiede alcune figure - probabilmente perché è più un caso particolare che capireisThisYearALeapYear
Axeman

4

Bene, la sintassi è orribile. Trovo molto utile se funzionale, e spesso rende il codice più leggibile.

Suggerirei di creare una macro per renderla più leggibile, ma sono sicuro che qualcuno può inventare un orribile caso limite (come sempre accade con CPP).


molte implementazioni e varianti BASIC hanno una funzione IF che sostituisce l'operatore ternario. Ho visto una serie di codebase con quella definita come macro in C.
Sparr,

Beh, stavo pensando a linguaggi di programmazione funzionali, ma sì.
Marcin,

"Realizzare una macro per renderla più leggibile" sei proprio un burlone!
niXar,

4

Mi piace usare l'operatore nel codice di debug per stampare i valori di errore, quindi non devo cercarli sempre. Di solito lo faccio per le stampe di debug che non rimarranno una volta terminato lo sviluppo.

int result = do_something();
if( result != 0 )
{
  debug_printf("Error while doing something, code %x (%s)\n", result,
                result == 7 ? "ERROR_YES" :
                result == 8 ? "ERROR_NO" :
                result == 9 ? "ERROR_FILE_NOT_FOUND" :
                "Unknown");
}


4

Non uso quasi mai l'operatore ternario perché ogni volta che lo uso, mi fa sempre pensare molto di più di quanto non debba fare in seguito quando provo a mantenerlo.

Mi piace evitare la verbosità, ma quando renderà il codice molto più facile da raccogliere, proverò la verbosità.

Tener conto di:

String name = firstName;

if (middleName != null) {
    name += " " + middleName;
}

name += " " + lastName;

Ora, è un po 'prolisso, ma lo trovo molto più leggibile di:

String name = firstName + (middleName == null ? "" : " " + middleName)
    + " " + lastName;

o:

String name = firstName;
name += (middleName == null ? "" : " " + middleName);
name += " " + lastName;

Sembra solo comprimere troppe informazioni in troppo poco spazio, senza chiarire cosa sta succedendo. Ogni volta che vedo un operatore ternario usato, ho sempre trovato un'alternativa che sembrava molto più facile da leggere ... poi di nuovo, è un'opinione estremamente soggettiva, quindi se tu e i tuoi colleghi trovate il ternario molto leggibile, provatelo.


1
Non è esattamente la stessa cosa però. Nel secondo esempio stai comprimendo tutte e tre le istruzioni in una riga. Questo è ciò che riduce la leggibilità, non l'operatore ternario.
ilitirit,

Abbastanza giusto, ho aggiornato per incorporare il tuo commento, ma mi sembra ancora ingombra ... ma ancora una volta, è soggettivo ... Non sto dicendo che il ternario non è leggibile, sto dicendo che non è leggibile per me (99 % delle volte)
Mike Stone,


3

Di solito uso in cose come questa:

before:

if(isheader)
    drawtext(x,y,WHITE,string);
else
    drawtext(x,y,BLUE,string);

after:

    drawtext(x,y,isheader==true?WHITE:BLUE,string);

Naturalmente nella maggior parte delle lingue, non avresti nemmeno bisogno della parte "== vera" di quel ternario.
Michael Haren,

Mi rendo conto che, anche se tendo a inserirlo solo per rendere il codice più leggibile dal momento che il compilatore dovrebbe ottimizzarlo allo stesso modo di senza == true comunque
KPexEA

in nessuna lingua potresti aver bisogno di "== true"
niXar

Ho avuto difficoltà a decidere se votare o meno. L'esempio è buono ma == TRUE è qualcosa che non sopporto di vedere nel codice di altre persone.
Peter Perháč,

3

Come altri hanno sottolineato, sono carini per brevi e semplici condizioni. Mi piace soprattutto loro per default (un po 'come il || e o l'utilizzo in javascript e pitone), ad esempio,

int repCount = pRepCountIn ? *pRepCountIn : defaultRepCount;

Un altro uso comune è inizializzare un riferimento in C ++. Poiché i riferimenti devono essere dichiarati e inizializzati nella stessa istruzione, non è possibile utilizzare un'istruzione if.

SomeType& ref = pInput ? *pInput : somethingElse;

2
Incredibile che questa sia la prima menzione di riferimenti di inizializzazione, che è uno dei pochi posti in cui "se" non può essere usato al posto di?:. (Suppongo che questa non sia una domanda specifica per C ++ ...) Sono utili anche negli elenchi di inizializzazione del costruttore, per lo stesso motivo.
j_random_hacker,

2

Tratto gli operatori ternari come GOTO. Hanno il loro posto, ma sono qualcosa che dovresti evitare di solito per rendere il codice più facile da capire.


2

Di recente ho visto una variazione sugli operatori ternari (beh, una specie di) che rende la variante standard "()?:" Sembra essere un esempio di chiarezza:

var Result = [CaseIfFalse, CaseIfTrue][(boolean expression)]

o, per fare un esempio più tangibile:

var Name = ['Jane', 'John'][Gender == 'm'];

Intendiamoci, questo è Javascript, quindi cose del genere potrebbero non essere possibili in altre lingue (per fortuna).


1
wow, è terribile! immagina di nidificarne un paio insieme! L'unica cosa vagamente utile che posso vedere è che se avessi una funzione che ha restituito un array di 2 elementi: var Name = getNames () [Gender == 'm']; ... ma è anche MENO leggibile!
nickf

2

Per casi semplici, mi piace usarlo. In realtà è molto più facile leggere / codificare ad esempio come parametri per funzioni o cose del genere. Anche per evitare la nuova linea mi piace mantenere tutto il mio if / else.

Neseting sarebbe un grande NO-NO nel mio libro.

Quindi, riprendendo, per un singolo if / else userò l'operatore ternario. Per altri casi un normale if / else if / else (o switch)


2

Mi piace il caso speciale di Groovy dell'operatore ternario, chiamato operatore Elvis:?:

expr ?: default

Questo codice valuta expr se non è null e, in caso contrario, predefinito. Tecnicamente non è davvero un operatore ternario, ma è sicuramente correlato ad esso e consente di risparmiare molto tempo / digitazione.


Sì, lo adoro anch'io - è ??in C #, l'operatore di coalescenza nulla: stackoverflow.com/questions/278703/…
Jarrod Dixon

2

Per compiti semplici come assegnare un valore diverso a seconda di una condizione, sono grandi. Non li userei quando ci sono espressioni più lunghe a seconda della condizione.


2

Molte risposte hanno detto, dipende . Trovo che se il confronto ternario non è visibile in una rapida scansione del codice, non dovrebbe essere usato.

Come problema secondario, potrei anche notare che la sua stessa esistenza è in realtà un po 'un'anomalia a causa del fatto che in C, i test di confronto sono un'affermazione. In Icon, il ifcostrutto (come la maggior parte di Icon) è in realtà un'espressione. Quindi puoi fare cose come:

x[if y > 5 then 5 else y] := "Y" 

... che trovo molto più leggibile di un operatore di confronto ternery. :-)

Recentemente è stata discussa la possibilità di aggiungere l' ?:operatore a Icon, ma diverse persone hanno correttamente sottolineato che non era assolutamente necessario a causa del modoif funziona.

Ciò significa che se potessi farlo in C (o in una qualsiasi delle altre lingue che hanno l'operatore ternery), in realtà non avresti affatto bisogno dell'operatore ternery.


2

Se tu e i tuoi compagni di lavoro capite cosa fanno e non vengono creati in grandi gruppi, penso che rendano il codice meno complesso e più facile da leggere perché c'è semplicemente meno codice.

L'unica volta in cui penso che gli operatori ternari rendano il codice più difficile da capire è quando hai più di 3 o 4 in una riga. La maggior parte delle persone non ricorda che hanno la giusta precedenza basata e quando ne hai una pila rende la lettura del codice un incubo.

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.