89

For example, would you prefer this 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;
}

or an if/else solution involving multiple return statements?

When is ?: appropriate, and when is it not? Should it be taught to or hidden from beginners?

10
  • 227
    This particular use of it is :) Dec 20, 2010 at 16:48
  • 7
    Who coded that, and what does their version of a median for four numbers look like? Or five? Dec 20, 2010 at 21:56
  • 4
    The more correct name is 'conditional operator'. It just happens to be the most common ternary operator in use. Dec 21, 2010 at 15:11
  • 2
    This was asked over two years ago on stackoverflow. Are we going to re-ask everything over here now? stackoverflow.com/questions/160218/to-ternary-or-not-to-ternary
    – webbiedave
    Dec 21, 2010 at 16:30
  • 3
    I am surprised why such questions keep coming up. The answer is always "whatever works and is readable." --the last one being equally important.
    – Apoorv
    Nov 26, 2012 at 6:18

25 Answers 25

248

Is the ternary operator evil?

No it's a blessing.

When is ?: appropriate?

When it's something so simple you don't want to waste many lines for.

and when is it not?

When the readability and clearness of code suffers and a potential for a mistake through insufficient attention increases, for example, with many chained operators, just like in your example.


The litmus test is when you begin to doubt your code is easily readable and maintainable in the long run. Then don't do it.

11
  • 25
    +1 for When the readability and clearness of code suffers. With many chained operators, just like in your example. The example takes longer to understand than equivalent if/else's.
    – sange
    Dec 20, 2010 at 16:44
  • 24
    +1 bravo for the great explanation! Developers don't tend to realise that some things are judgement calls, they want everything to be black and white. It drives me nuts. I've encountered to many people of the opinion "X is evil, lets never use it.". I prefer "X is great if you use it for what it's good at". Dec 20, 2010 at 16:48
  • 55
    It is also evil if it's used: myVar = (someExpression) ? true : false; Aaaaarrgh!
    – adamk
    Dec 20, 2010 at 17:55
  • 21
    @adamk: Try this for evil: myVar = someExpression ? false : true; Dec 20, 2010 at 22:00
  • 11
    How about (someExpression ? var1 : var2)++ :-) Dec 21, 2010 at 10:42
55

I think the unnested ternary operator (i.e., a statement where it's used only once) is fine, but if you're nesting more than one, it becomes somewhat hard to read.

3
  • 3
    This might be considered an oversimplification, but it's a very easy guideline to follow and it works in most cases. Dec 21, 2010 at 15:08
  • 2
    It's actually my rule of thumb: you should never nest them, otherwise replace them with if/else's, it will be clearer that way.
    – Piovezan
    Jan 28, 2014 at 19:06
  • If you would use them, and would nest them, then for the love of humanity use parenthesis and white space to make it readable. If-else can be made just as ugly. Resist the urge to show off how 'smart' you are by writing things that compilers can read but humans can't. Someday you will be the human who can't. Aug 29, 2014 at 3:00
26

When is ?: appropriate

  • When it makes your code more concise and readable.

and when is it not?

  • When it makes your code unreadable.
  • If you're doing it just to please a refactoring tool like ReSharper and not the person who has to maintain the code

If you have any logic or function calls inside the ternary expression, you're making it horrible to look at.

1
  • This one deserves a lot of upvotes!
    – Piovezan
    Jan 28, 2014 at 19:07
25

One difference that (I think) no-one has pointed out is that if-else can't return a value, whereas the ternary operator can.

Coming from F#, I sometimes like to use the ternary operator to mimic pattern matching.

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

vs

return val == A ? 1 : 
       val == B ? 3 : 
       0;
5
  • That's pretty cool. Never thought of that. Dec 21, 2010 at 14:14
  • +1 @Benjol: I was going to point out the same thing (that in F#, everything is an expression, including if/elif/else). I use ternaries like in your example too, so far also undiscovered :). Another thing I've been doing, in Javascript, perhaps over the top, is: var res = function() {switch(input) {case 1: return "1"; case 2: return "2"; ...}}() to emulate switches as expressions. Dec 21, 2010 at 15:05
  • @Stephen, I was going to use the words expression and statement but I'm always worried I'll get them the wrong way round and make a fool of myself :)
    – Benjol
    Dec 22, 2010 at 6:02
  • @Benjol: I know what you mean! Dec 22, 2010 at 13:16
  • 6
    Also useful in C and C++ for initializing const variables that can't be changed later. Jan 25, 2011 at 19:53
14

An example (IMHO) of a valid use:

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

This results in more readable code than having 2 distinct print statements. Nested examples depend: (understandable ? yes : no)

2
  • 12
    Just keep in mind that if you do this, you're making it hell for whoever has to localize your application. Of course, if that's not a problem, go right ahead.
    – Anon.
    Dec 20, 2010 at 20:23
  • 1
    That's my rule of thumb: 1 level of nesting (under some circumstances). Dec 20, 2010 at 22:56
10

Absolutely not evil. In fact, it's pure, and if-then-else isn't.

In functional languages like Haskell, F#, ML etc., it's the if-then-else statements that are considered evil.

The reason for this is that any "action" like an imperative if-then-else statement requires you to separate a variable declaration from its definition, and introduces state to your function.

For instance, in the following code:

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

vs.

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

The first one has two advantages aside from being shorter:

  1. x is a constant, and so offers much fewer chance of introducing bugs, and can potentially be optimized in ways the second could never be.
  2. The type is made clear by the expression, so the compiler can effortlessly infer that x needs to be of type Parity.

Confusingly, in functional languages, the ternary operator is often called if-then-else. In Haskell, you might say x = if n mod 3 == 1 then Odd else Even.

1
  • yep, this is the point @Benjol made as well. See my comment to his answer for a fun way of emulating switch statements as expressions in Javascript. Dec 21, 2010 at 15:10
8

That particular expression makes my eyes hurt; I'd lash out an any developer on my team that used it because it's unmaintainable.

Ternary operators are not evil when used well. They don't even have to be single lines; A long one that is formatted well can be very clear and easy to understand:

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

I like that better than the equivalent if/then/else chain:

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

return $retval;

I'll reformat those into:

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

return $retval;

if the conditions and assignments allow easy alignment. Still I prefer the ternary version because it's shorter and doesn't have as much noise around the conditions and assignments.

1
  • Why can't I put linebreaks in comments? Arrgghh! Jan 25, 2011 at 20:36
4

ReSharper in VS.NET sometimes suggests to replace if...else with the ?: operator.

It seems that ReSharper suggests only if the conditions/blocks are below a certain complexity level, otherwise it sticks with if...else.

1
  • 4
    another great feature I love about ReSharper Dec 20, 2010 at 21:39
4
  1. "Evil" arguments aside, in my experience I've found a high correlation between a programmer's use the ternary operator and the likelihood of his or her entire codebase being difficult to read, follow, and maintain (if not outright undocumented). If a programmer's more concerned with saving a few 1-2 character lines than someone being able to understand his or her code, then any minor confusion understanding a ternary statement is usually the tip of the iceberg.

  2. Ternary operators attract magic numbers like s**t attracts flies.

If I was looking for an Open Source library to solve a particular problem, and I saw code such as the original poster's ternary operators in a candidate for said library, warning bells would start going off in my head and I'd start considering moving on to some other project to borrow from.

4

Here's an example of when it is evil:

oldValue = newValue >= 0 ? newValue : oldValue;

It's confusing and wasteful. The compiler could optimize out the second expression (oldValue = oldValue), but why did the coder do this in the first place?

Another doozy:

thingie = otherThingie != null ? otherThingie : null;

Some people are just not meant to be coders...

Greg says that the equivalent if statement is 'noisy'. It is if you write it noisily. But that same if can be written as:

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

Which is no noisier than the ternary. I wonder if the ternary short-cuts; do all of the expressions get evaluated?

1
  • Your second example reminds me of if (x != 0) x = 0;... Jan 25, 2011 at 19:55
3

Anything that makes your code uglier is evil.

If you use ternary to make your code cleaner then sure use it. Sometimes in like php it's great to do inline substitutions, e.g.

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

That saves a few lines, and it pretty clear, but your example needs at least better formatting to be clear, and ternary isn't really good for multi-line, then you might as well use if/else.

3

Far from being evil, the ternary operator is a godsend.

  • It is most useful when you want to make a decision in a nested expression. The classic example is a function call:

    printf("I see %d evil construct%s in this program\n", n, n == 1 ? "" : "s");
    
  • In your particular example, the ternary is nearly gratuitous, since it is the top-level expression under a return. You can lift the conditional out to the statement level without duplicating anything other than the return keyword.

N.B. Nothing will ever make that particular algorithm for median easy to read.

1
  • It's hard to be so readable that you can't make it better. printf("I see %d evil construct%s in this program\n", n, "s" unless (n == 1) "s");
    – Pacerier
    Feb 6, 2015 at 13:48
3

Evil? Look, they're just different.

if is a statement. (test ? a : b) is an expression. They're not the same thing.

Expressions exist to express values. Statements exist to perform actions. Expressions can appear inside statements, but not vice-versa. So you can use ternary expressions within other expressions, like for terms in a summation, or for arguments to a method, and so on. You don't have to, but you can if you want to. There's nothing wrong with that. Some people might say that's evil, but that's their opinion.

One value of a ternary expression is it makes you to handle both true and false cases. if statements don't.

If you're worried about readability, you can format them readably.

Somehow "evil" crept into the programming vocabulary. I'd love to know who first dropped it. (Actually, I have a suspect - he's at MIT.) I would rather we had objective reasons for value judgements in this field, not just peoples' taste and name-calling.

2
  • 1
    May I have a hint on who the suspect is? Just to improve my knowledge of the field a bit.
    – mlvljr
    Jan 26, 2011 at 10:52
  • 1
    @mlvljr: Well I could be wrong, so better not to. Jan 26, 2011 at 16:52
2

It has a place. I've worked at a lot of companies where the skill levels of developers range from terrible to wizard. Since the code has to be maintained, and I won't be there forever, I try to write stuff so that it looks like it belongs there (without looking at the comments with my initials, it is extremely rare for you to be able to look at code I've worked on to see where I made changes), and that someone with less skill than myself can maintain it.

While the ternary operator looks nitziffic and way cool, my experience is that line of code is going to be about impossible to maintain. At my current employer, we have products that have been shipping for almost 20 years. I wouldn't use that example anywhere.

2

I do not think that the ternary operator is evil.

Here is a gotcha that had me stumped, though. I was a C programmer for many (10+) and in the late 1990s I moved into web based application programming. As a web programmer, I soon ran across PHP which also has a ternary operator. I had a bug in a PHP program which I finally traced to a line of code with a nested ternary operator. It turns out that the PHP ternary operator associated left to right but the C ternary operator (which I was used to) associates right to left.

2

This can be reformatted to be as nice-looking as the if/else combination:

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;
}

But the problem is that I am not really sure if I got the indentation right to represent what will actually happen. :-)

4
  • 3
    +1 I think this is far better than an equivalent if-else structure. The key is the formatting.
    – Orbling
    Dec 20, 2010 at 22:13
  • 15
    If I saw this in a code base, I would seriously consider looking for a new job. Dec 21, 2010 at 14:50
  • +1 Not for this actual indentation, but this is the best solution for this example.
    – Mark Hurd
    Jan 26, 2011 at 2:32
  • 2
    Only that another accidental automatic formatting would wipe out all that indenting, and time for another round of restructuring - hugely productive :)
    – nawfal
    Apr 23, 2013 at 19:43
2

Can I say it? I can't manage to find this particular application of the ternary operation evil:

  1. the operation it performs is pretty trivial, and once you went trough it once it's hardly possible some bugs will come out;
  2. what it does is clearly stated in the function name;
  3. taking >1 line for something so obvious and that so clearly wouldn't be improved in the future (unless a magic median algorithm has lived undetected until now).

Please have mercy, my reputation is pretty pitiful already.

2

Biggest win: Showing that there is a single target of action.

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

There are two code paths that you can follow, and the reader must read carefully to see which two variables are being set. In this case, it's only one variable, but the reader has more to read to figure that out. After all, it could have been this:

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

With the ternary operator, it's clear that only one variable is being set.

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

At the very lowest level, it is the DRY (Don't Repeat Yourself) principle at its most basic. If you can specify $foo only once, do so.

1

If ... then ... else tends to emphasize the condition and therfore de-emphasize the operations being conditionally done.

the ternary operator is the opposite, it tends to hide the condition and is therfore useful when the operation being done is more important than the condition itself.

There is the minor technical niggle, in some languages, that they aren't quite interchangeble due to one being a statement and one an expression e.g. conditionally initialising consts in C++

1

When is appropriate, and when is it not?

I think that when developing for a homogeneous group of people, there is no problem but when you have to deal with people that handle different levels, this kind of oneliners only introduce a further level of complexyti to the code. So, my policy on the matter is: code clear and dont explain rather than code short and explain 123123 times.

Should it be taught to or hidden from beginners?

I should not be taught to beginners, rather prefert them to figure it out when need emerges, so it'll be used only when necesary and not every time you need an if.

1

IMO, the operator itself isn't evil, but the syntax used for it in C (and C++) is excessively terse. IMO, Algol 60 did it better, so something like this:

A = x == y ? B : C;

would look more like this (but sticking to C-like syntax in general):

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

Even with that, excessively deep nesting can lead to problems with readability, but at least A) anybody who's done programming at all can figure it out a simple one, and B) people who understand it can handle considerably deeper nesting pretty easily. OTOH, I'd also note that in LISP (for example) a cond is pretty much like a ternary statement -- not a set of statements, but a single expression the yields a value (then again, most of LISP is like that...)

3
  • Why not just do this for readability? A = (x==y) ? B : C
    – Jeremy
    Jan 25, 2011 at 20:22
  • @Jeremy: while some people find the parens useful, even at best they don't help much. Nest more than a couple deep and you still need careful indentation (as a bare minimum) to keep things sorted out. Undoubtedly the same would happen eventually in Algol, but I never say a problem arise in it like I often do in C... Jan 25, 2011 at 20:28
  • I just assumed everyone was in agreement that nesting a ternary operator is bad. I was speaking specifically about the examples you provided. In particular, how the first one can be more like the second one in most languages.
    – Jeremy
    Jan 25, 2011 at 20:31
1

A shop that regularly writes 600-1200-line methods should not tell me that a ternary is "hard to understand". Any shop that regularly allows five conditions to evaluate a code branch should not tell me that concretely summarized conditions in a ternary are "hard to read".

1

When is ?: appropriate, and when is it not?

  • If you don't get a performance gain, don’t use it; it affects the readability of your code.
  • Use it once and don’t nest it.
  • It’s harder to debug.

Should it be taught to or hidden from beginners?

Doesn't matter, but it should not be intentionally hidden as it's not too complex for a “beginner” to learn.

-1

In your example:

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

is very simple to read, and obvious. The variable between the < < is the return value.

Update

same, but fewer lines of code. Still simple I think.

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
2
  • This requires 12 comparisons in the worst case... Jan 25, 2011 at 20:58
  • 1
    Perhaps, but it's legible. Jan 25, 2011 at 21:29
-2

It's also necessary for const

const int nLegs  = isChicken ? 2: 4 ;
3
  • Strange. I think its C++ or something. I thought const had always been compile time constant (as in C#)
    – nawfal
    Apr 23, 2013 at 19:48
  • @nawfal - if you don't know isChicken until runtime Apr 23, 2013 at 22:47
  • yes thats what. i think const is so in certain languages. In C# const should always be compile time known value. which means const int nLegs = isChicken ? 2: 4 ; wont work, but const int nLegs = true ? 2: 4 ; will
    – nawfal
    Apr 24, 2013 at 4:04

Not the answer you're looking for? Browse other questions tagged or ask your own question.