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 usestd::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'tnullptr
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 needif
/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
C++ Dll Export: Decorated/Mangled Names
How to Programmatically Get the Version of a Dll or Exe File
Requesting Administrator Privileges At Run Time
Determine If a Type Is an Stl Container At Compile Time
Append an Int to a Std::String
How Does This Template Magic Determine Array Parameter Size
Using Unicode in C++ Source Code
Conversion of 2D Array to Pointer-To-Pointer
How to Pass a Reference to a Two-Dimensional Array to a Function
C++: Constructor Initializer For Arrays
Non-Blocking Console Input C++
How to Check If a C++ String Is an Int
Using Strtok With a Std::String
Is Calling Destructor Manually Always a Sign of Bad Design