Ternary Operator : VS If...Else

Benefits of ternary operator vs. if statement

Performance

The ternary operator shouldn't differ in performance from a well-written equivalent if/else statement... they may well resolve to the same representation in the Abstract Syntax Tree, undergo the same optimisations etc..

Things you can only do with ? :

If you're initialising a constant or reference, or working out which value to use inside a member initialisation list, then if/else statements can't be used but ? : can be:

const int x = f() ? 10 : 2;

X::X() : n_(n > 0 ? 2 * n : 0) { }

Factoring for concise code

Keys reasons to use ? : include localisation, and avoiding redundantly repeating other parts of the same statements/function-calls, for example:

if (condition)
return x;
else
return y;

...is only preferable to...

return condition ? x : y;

...on readability grounds if dealing with very inexperienced programmers, or some of the terms are complicated enough that the ? : structure gets lost in the noise. In more complex cases like:

fn(condition1 ? t1 : f1, condition2 ? t2 : f2, condition3 ? t3 : f3);

An equivalent if/else:

if (condition1)
if (condition2)
if (condition3)
fn(t1, t2, t3);
else
fn(t1, t2, f3);
else if (condition3)
fn(t1, f2, t3);
else
fn(t1, f2, f3);
else
if (condition2)
...etc...

That's a lot of extra function calls that the compiler may or may not optimise away.

Further, ? allows you to select an object, then use a member thereof:

(f() ? a : b).fn(g() ? c : d).field_name);

The equivalent if/else would be:

if (f())
if (g())
x.fn(c.field_name);
else
x.fn(d.field_name);
else
if (g())
y.fn(c.field_name);
else
y.fn(d.field_name);

Can't named temporaries improve the if/else monstrosity above?

If the expressions t1, f1, t2 etc. are too verbose to type repeatedly, creating named temporaries may help, but then:

  • To get performance matching ? : you may need to use std::move, except when the same temporary is passed to two && parameters in the function called: then you must avoid it. That's more complex and error-prone.

  • c ? x : y evaluates c then either but not both of x and y, which makes it safe to say test a pointer isn't nullptr before using it, while providing some fallback value/behaviour. The code only gets the side effects of whichever of x and y is actually selected. With named temporaries, you may need if / else around or ? : inside their initialisation to prevent unwanted code executing, or code executing more often than desired.

Functional difference: unifying result type

Consider:

void is(int) { std::cout << "int\n"; }
void is(double) { std::cout << "double\n"; }

void f(bool expr)
{
is(expr ? 1 : 2.0);

if (expr)
is(1);
else
is(2.0);
}

In the conditional operator version above, 1 undergoes a Standard Conversion to double so that the type matched 2.0, meaning the is(double) overload is called even for the true/1 situation. The if/else statement doesn't trigger this conversion: the true/1 branch calls is(int).

You can't use expressions with an overall type of void in a conditional operator either, whereas they're valid in statements under an if/else.

Emphasis: value-selection before/after action needing values

There's a different emphasis:

An if/else statement emphasises the branching first and what's to be done is secondary, while a ternary operator emphasises what's to be done over the selection of the values to do it with.

In different situations, either may better reflect the programmer's "natural" perspective on the code and make it easier to understand, verify and maintain. You may find yourself selecting one over the other based on the order in which you consider these factors when writing the code - if you've launched into "doing something" then find you might use one of a couple (or few) values to do it with, ? : is the least disruptive way to express that and continue your coding "flow".

Ternary operator ?: vs if...else

Depends on your compiler, but on any modern compiler there is generally no difference. It's something you shouldn't worry about. Concentrate on the maintainability of your code.

Performance of ternary operator vs if-else statement

I doubt there is a performance difference. They compile to equivalent sequences of bytecodes:

>>> def f():
... return a if b else c
...
>>> dis.dis(f)
2 0 LOAD_GLOBAL 0 (b)
2 POP_JUMP_IF_FALSE 8
4 LOAD_GLOBAL 1 (a)
6 RETURN_VALUE
>> 8 LOAD_GLOBAL 2 (c)
10 RETURN_VALUE
>>> def g():
... if b:
... return a
... else:
... return c
...
>>> dis.dis(g)
2 0 LOAD_GLOBAL 0 (b)
2 POP_JUMP_IF_FALSE 8

3 4 LOAD_GLOBAL 1 (a)
6 RETURN_VALUE

5 >> 8 LOAD_GLOBAL 2 (c)
10 RETURN_VALUE
12 LOAD_CONST 0 (None)
14 RETURN_VALUE

As with most performance questions, the answer is to measure.

Is ternary operator less efficient than an if statement that sets a different value to a variable

In your case, your ternary operation and your if statement are not the same, since you don't have an else statement after if, so it only checks whether a>b.

If you are interested in the question about the performance difference in case of semantically equal Ternary operation and if-else block, then the answer is No, there is no much of the difference. Ternary Operator is just a syntactic sugar of writing if-else.

Here is the bytecode comparison in the simplest Java program, with only one (an entry-point) main method, where in first case I implement Ternary Operator, and in the second one - if-else statement.

 //First example, having Ternary Operator
public static void main(java.lang.String[]);
Code:
0: iconst_0
1: istore_1
2: iconst_1
3: istore_2
4: iload_1
5: iload_2
6: if_icmple 13
9: iload_2
10: goto 14
13: iload_1
14: istore_1
15: return
}


//Second Example, having if-else alternative
public static void main(java.lang.String[]);
Code:
0: iconst_0
1: istore_1
2: iconst_1
3: istore_2
4: iload_1
5: iload_2
6: if_icmple 14
9: iload_2
10: istore_1
11: goto 16
14: iload_1
15: istore_1
16: return
}

can I use `else if` with a ternary operator?

Unlike an if with optional else or optional else if branches, a ternary operator has two and only two branches.

It's actually a part of the name. Where + in a + b is a binary operator, that is it has two operands, ? has three, as in a ? b : c, and is termed ternary because of that. Technically there could be other ternary operators beyond ? but in most languages they don't exist, so it is generally understood that the name "ternary" means the ? operator.

You can have else if like functionality if you sub-branch the second clause:

a ? b : (c ? d : e)

This is usually a bad idea as ternary operations can be messy to start with and layering like this is usually an express train to unmaintainable code.

It is much better to write:

if (a) {
b
}
else if (c) {
{
d
}
else {
e
}

This is more verbose, but abundantly clear.

If you use ternaries too agressively you'll end up with code like:

a()?c?d?e:f:g:h?i(j?k:l?m:n):o

Where it's anyone's guess what's going on in there.

Use of ternary operator instead of if-else in C++

No. In general the conditional operator is not a replacement for an if-else.

The most striking difference is that the last two operands of the conditional operator need to have a common type. Your code does not work eg with:

std::string do_this() {return {};}
void do_that() {}

There would be an error because there is no common type for void and std::string:

<source>: In function 'int main()':
<source>:15:22: error: third operand to the conditional operator is of type 'void', but the second operand is neither a throw-expression nor of type 'void'
15 | my_flag ? do_this() : do_that();
| ~~~~~~~^~

Moreover, the conditional operator is often less readable.

The conditional operator can be used for complicated in-line initialization. For example you cannot write:

 int x = 0;
int y = 0;
bool condition = true;
int& ref; // error: must initialize reference
if (condition) ref = x; else ref = y; // and even then, this wouldn't to the right thing

but you can write

 int& ref = condition ? x : y;

My advice is to not use the conditional operator to save some key-strokes compared to an if-else. It is not always equivalent.

PS: The operator is called "conditional operator". The term "ternary operator" is more general, like unary or binary operator. C++ just happens to have only a single ternary operator (which is the conditional operator).

Complexity: Conditional operator vs if-else

There is no difference, both constructs are in Theta(1), so constant time.

Not talking about their content, obviously. But in your case even the content is in constant time. So both of your snippets run in Theta(1) time.

Java ternary operator vs if/else in JDK8 compatibility

When you think about the type of the operands, the problem becomes more apparent:

this.method != null ? this.method : this.constructor

has as type the most specialized common type of both the operands, i.e. the most specialized type common to both this.method and this.constructor.

In Java 7 this is java.lang.reflect.Member, however the Java 8 class library introduces a new type java.lang.reflect.Executable which is more specialized than the generic Member. Hence with a Java 8 class library the result type of the ternary expression is Executable rather than Member.

Some (pre-release) versions of the Java 8 compiler seem to have produced an explicit reference to Executable inside generated code when compiling the ternary operator. This would trigger a class load, and thus in turn a ClassNotFoundException at runtime when running with a class library < JDK 8, because Executable only exists for JDK ≥ 8.

As noted by Tagir Valeev in this answer, this is actually a bug in pre-release versions of JDK 8 and has since been fixed, so both the if-else workaround and the explanatory comment are now obsolete.

Additional note: One might come to the conclusion that this compiler bug was present before Java 8. However, the byte code generated for the ternary by OpenJDK 7 is the same as the byte code generated by OpenJDK 8. In fact, the type of the expression goes completely unmentioned at runtime, the code is really only test, branch, load, return without any additional checks going on. So rest assured that this is not a problem (anymore) and indeed seems to have been a temporary problem during development of Java 8.

nested ternary operator vs nested if else, which is better in readability purpose

Just reformatting your code makes it quite clear:

ColorEnum color = 
opacity == Opacity.FIVE ? ColorEnum.BLACK
: opacity == Opacity.TEN ? ColorEnum.WHITE
: opacity == Opacity.FIFTY ? ColorEnum.RED
: opacity == Opacity.TWENTY ? ColorEnum.BLUE
: opacity == Opacity.FIFTEEN ? ColorEnum.PURPLE
: null;

LISP adopts the cond construct which has both the same structure and the same semantics, and is considered good practice. As an aside, Clojure also supports a form which tests the value of a single expression with a single predicate applied to different values (one for each clause) and calls it condp—that would be a perfect match for your use case.

The idiom with the ternary operator has the advantage over an if-else cascade for being an expression so you need only a single statement to assign it to the variable. if-else will force you to pull the assignment into each then clause, introducing more boilerplate and more opportunity to fail on correctness.

A switch statement could also be considered as an alternative, but it would have the following deficiencies:

  • like if-else, it is not an expression;

  • you are restricted to just different constant values of a single expression (the type of the expression being quite constrained, too).

  • it's prone to bugs due to the boilerplate break missing somewhere.

Ternary ? operator vs the conventional If-else operator in c#

I ran 100 million Ternary Operators and 100 million If-Else statements and recorded the performance of each. Here is the code:

Stopwatch s = new Stopwatch();
// System.Diagnostics Stopwatch
int test = 0;
s.Start();
for(int a = 0; a < 100000000; a++)
test = a % 50 == 0 ? 1 : 2;
s.Stop();

s.Restart();
for(int b = 0; b < 100000000; b++)
{
if(b % 50 == 0)
test = 1;
else
test = 2;
}
s.Stop();

Here is the results (ran on an Intel Atom 1.66ghz with 1gb ram and I know, it sucks):

  • Ternary Operator: 5986 milliseconds or 0.00000005986 seconds per each operator.

  • If-Else: 5667 milliseconds or 0.00000005667 seconds per each statement.

Don't forget that I ran 100 million of them, and I don't think 0.00000000319 seconds difference between the two matters that much.



Related Topics



Leave a reply



Submit