Jump to content

Ternary conditional operator

From Wikipedia, the free encyclopedia
This is an old revision of this page, as edited by Capi (talk | contribs) at 20:51, 26 February 2008 (Python: the if-then-else expression only exists as of Python 2.5. Mention this, and offer an alternative that always works.). The present address (URL) is a permanent link to this revision, which may differ significantly from the current revision.

?: is a ternary operator that is part of the syntax for a basic conditional expression in several programming languages including C, Objective-C, C++, C#, D, Java, JavaScript, Linoleum, Perl, PHP, Tcl, Ruby, and Verilog. Its origin comes from BCPL, whose equivalent syntax for E1 ? E2 :E3 was E1 -> E2, E3[1]. Languages derived from BCPL tend to feature this operator. Some other languages such as Haskell have an if-else expression (rather than statement) which behaves similarly.

Conditional assignment

?: is most frequently used in conditional assignment statements. When used this way, it is used in an expression as follows:

condition ? value if true : value if false 

The condition is evaluated true or false as a Boolean expression. On the basis of the evaluation of the Boolean condition, the entire expression returns value if true if condition is true, but value if false otherwise. This is similar to the way conditional expressions (if-then-else constructs) work in functional programming languages.

Usage

This ternary operator's most common usage is to minimize the amount of code used for a simple conditional assignment statement. (In this case, the expression is converted into a statement by appending a semicolon ; to the expression.) For example, if we wish to implement some C code to change a shop's opening hours to 12 o'clock in weekends, and 9 o'clock on weekdays, we may use

int opening_time = (day == WEEKEND) ? 12 : 9;

instead of the more verbose

int opening_time;

if (day == WEEKEND)
    opening_time = 12;
else
    opening_time = 9;

The two forms are equivalent. Note that neither value if true nor value if false expressions can be omitted from the ternary operator without an error report upon parsing. This contrasts with if..else statements, where the else clause can be omitted.

A GNU extension to C allows the second operator to be omitted, as in

  a = x ? : y;

which returns the value of the first operator if it is non-false, and otherwise returns the value of the third operator. The expression is equivalent to

  a = x ? x : y;

except that if x is an expression, it is evaluated only once. The difference is significant if evaluating the expression has side effects.

C++

In C++ there are conditional assignment situations where use of the if-else statement is not possible, since this language explicitly distinguishes between initialization and assignment. In such case it is always possible to use an inline function call, but this is cumbersome and inelegant. Use of the ?: operator is much better whenever possible. For example, if you want to pass conditionally different values as an argument for a constructor of a field or a base class, it is not possible to use a plain if-else statement; in this case we can use a conditional assignment expression, or a function call. Mind also that some types allow initialization, but do not allow assignment, or even the assignment operator does totally different things than the constructor. The latter is true for reference types, for example:

#include <iostream>
#include <fstream>
using namespace std;

int main ( int argc, char** argv )
{
    const char* name = 0;
    ofstream fout;
    if ( argc > 1 )
    {
        name = argv[1];
        fout.open ( name, ios::out | ios::app );
    }

    ostream& sout = name ? fout : cout;
}

In this case there's no possibility to replace the use of ?: operator with if-else statement. (Although we can replace the use of ?: with a call to a custom inline function, inside of which can be an if-else statement.)

The Python programming language uses a different syntax for this operator:

value_when_true if condition else value_when_false

This feature is not available for Python versions prior to 2.5, however. The Python programming FAQ mentions several possible workarounds for these versions, with varying degrees of simplicity versus semantic exactness (for example, regarding the short-circuit evaluation property of ?:). The most complete alternative, that has all the same properties as ?: and still works in Python versions prior to 2.5, would be:

(a and [b] or [c])[0]

Result type

Clearly the type of the result of the ?: operator must be in some sense the type unification of the types of its second and third operands. In C this is accomplished for numeric types by arithmetic promotion; since C does not have a type hierarchy for pointer types, pointer operands may only be used if they are of the same type (ignoring type qualifiers) or one is void or NULL. It is undefined behaviour to mix pointer and integral or incompatible pointer types; thus

number = spell_out_numbers ? "forty-two" : 42;

will result in a compile-time error in most compilers.

?: in style guidelines

Some corporate programming guidelines list the use of the ternary operator as bad practice because it can harm readability and long-term maintainability.[citation needed] However, when properly crafted the ternary operator is no more difficult to debug than the if statement equivalent (and in fact shouldn't require any debugging at all).[citation needed] Ternary operators are widely used and can be useful in certain circumstances to avoid the use of an if statement, either because the extra verbiage would be too lengthy or because the syntactic context does not permit a statement. For example:

#define MAX(a, b) (((a)>(b)) ? (a) : (b))

or

 for (i = 0; i < MAX_PATTERNS; i++)
    c_patterns[i].ShowWindow(m_data.fOn[i] ? SW_SHOW : SW_HIDE);

(The latter example uses the Microsoft Foundation Classes Framework for Win32.)

When properly formatted the ternary operator can be used to write simple and coherent case selectors. For example:

vehicle = arg == 'B' ? bus :
          arg == 'A' ? airplane :
          arg == 'T' ? train :
          arg == 'C' ? car :
          arg == 'H' ? horse :
          feet;

This is more readable and immediately recognized than an equivalent if/else or switch construction, and such code is also more likely to be bug free and maintained correctly as the assigned variable is stated only once.

Inconsistency of Implementations

Due to an unfortunate error in the language grammar, the implementation of ?: in the PHP language uses the incorrect associativity when compared to other languages, and given a value of T for arg, the PHP equivalent of the above example would yield the value horse instead of train as one would expect.

Conditional jumps

This ternary operator can also be used (though less commonly) in conditional jump statements, as in the low-level programming language Linoleum:

? logical comparison -> code label;

Although the usage and format are different, it is still a ternary operator (used as a conditional expression) because the three arguments come from the code label and from the two arguments in the logical comparison. (The -> operator, which signifies an unconditional jump, takes the place of the : operator.)

References

  1. ^ "BCPL Ternary operator (page 15)" (PDF). BCPL Reference Manual.