views:

507

answers:

8

(I don't have a serious need for this answer, I am just inquisitive.)

Can every if-else construct be replaced by an equivalent conditional expression using the conditional operator ?:?

A: 

The conditional operator expects to have both of the items following the ? be rvalues (since the result of a conditional operator is itself an rvalue) - so while I'm not entirely an expert on the C/C++ standards, my intuition would be that the following would be disallowed (or failing that, extremely poor coding style...):

(condition) ? return x : return y;

whereas the if-else version would be quite standard:

if(condition) return x;
else return y;

Now, that said, could you take any program and write a similarly functioning program that didn't use if-else? Sure, you probably could. Doesn't mean it would be a good idea, though. ;)

Amber
Thanks Dave, yes `(condition) ? return x : return y;` is not allowed the reason of which is that `return x` and `return y` are not expressions.The Syntax of conditional expression is `(expr1) ? expr2: expr3`
nthrgeek
Well, for the if-else construct you suggested I think this will be a equivalent conditional expression : `return (condition) ? x : y`
nthrgeek
Yes, it's equivalent - but that's not a direct replacement of the if-else construct, it's a reworking of the code (hence my final comment).
Amber
For instance, consider this instead: `if(condition) return x; else y=2;` - you'd have a very hard time converting that to a ternary. ;)
Amber
+2  A: 

Using the conditional operator results in an expression and both potential results of the conditional operator must be 'compatible' (convertible to the same type).

An if-else construct need not even 'return' any type much less the same one from both branches.

Michael Burr
+4  A: 

On the surface of it, no. The conditional operator is an expression (that is, it has a value), while if/else is a statement (thus has no value). They fulfill different "needs" within the language syntax.

However, since you can ignore expression values, and since any expression can be turned into a statement by adding a semicolon, you can essentially emulate if/else with a conditional expression and two auxiliary functions:

// Original code:
if (condition) {
  // block 1
}
else {
  // block 2
}

// conditional expression replacement:

bool if_block() {
  // block 1
  return true;
}

bool else_block() {
  // block 2
  return true;
}

// Here's the conditional expression.  bool value discarded:
condition ? if_block() : else_block();

However, having said that, I'm not sure it's anything more than a curiosity...

Drew Hall
Note, that the return value of type void is also allowed.
Michael Krelin - hacker
@hacker: Edited--thanks for the tip. Didn't realize you could have a void expression in a conditional clause!
Drew Hall
Digressing slightly, the return type of void is not allowed here: `int a = condition ? if_block() : else_block();` ? (gcc 4.3.2)
James Morris
@James: How does that jive with the ignored return value? Does it have implicit int type?
Drew Hall
@Drew: gcc says "error: void value not ignored as it ought to be" _in_my_example_ but other compilers maybe only issue a warning?
James Morris
@James: Edited it back to bool return type--I wasn't comfortable with the void expression there anyways! (Even if the discarded bools are a little less transparent).
Drew Hall
+1  A: 
if( cond )
    break;
else
    a=b;

can not always be replaced by ?: operator. You can often (if not always) rethink your whole code to provide for this substitute, but generally you can't put anything that controls execution into ?:. break, return, loops, throw, etc.

Michael Krelin - hacker
`throw` is an expression.
sdcvvc
+7  A: 

Does every if-else constructs can be replaced by an equivalent conditional expression using conditional operator?

No, you've asked this backwards. The "bodies" of if/else contain statements, and it is not possible to turn every statement into an expression, such as try, while, break statements, as well as declarations. Many "statements" are really expressions in disguise, however:

++i;
blah = 42;
some_method(a,b,c);

All of these are statements which consist of one expression (increment, assignment, function-call, respectively) and could be turned into expressions within a conditional.

So, let's reverse the question, since it sounds like you really want to know how equivalent if/else statements are to ternary conditional expressions: Can every conditional expression be replaced by equivalent if/else statements? Almost all, yes. A common example is return statements:

return cond ? t : f;
// becomes:
if (cond) return t;
else return f;

But also other expressions:

n = (cond ? t : f);
// becomes:
if (cond) n = t;
else n = f;

Which starts to point to where conditional expressions cannot be easily replaced: initializations. Since you can only initialize an object once, you must break up an initialization that uses a conditional into using an explicit temporary variable instead:

T obj (cond ? t : f);
// becomes:
SomeType temp;
if (cond) temp = t;
else temp = f;
T obj (temp);

Notice this is much more tedious/cumbersome, and requires something type-dependent if SomeType cannot be default-constructed and assigned.

Roger Pate
+1 for very good explanation.
nthrgeek
"The "bodies" of if/else contain statements, and it is not possible to turn every statement into an expression"--that's clears my all doubt. :)
nthrgeek
Also, initialization of a const variable cannot be broken up into an if statement: `const T obj = cond ? t : f;` <= cannot change without removing const.
Bill
Curiously enough, C++0x lets one turn any bunch of statements into an expression using lambdas.
Pavel Minaev
Bill: 'obj' could easily be made const in my example with `T obj (temp);`
Roger Pate
Roger: Yes, but you need the second variable. I wasn't trying to correct your final example, just adding another instance where ?: cannot be eaxactly converted.
Bill
A: 

GCC has statement expression, using it you can rewrite if statements to equivalent ?: expressions:

if (<expression>)
  <statement1>
else
  <statement2>

EDIT: The void casts serves two purpose. The subexpressions in ?: must have the same type, and without the void cast the compiler may print warning: statement with no effect.

(<expression>)? (void)({<statement1>}) : (void)({<statement2>});
sambowry
I think you should put the `void` thingy around the statement expressions - the cast operation is not distributive among the second and third operands.
Johannes Schaub - litb
@litb: can you write a short example where my void placement is wrong?
sambowry
sambowry: fails with GCC 4.3.3: `echo 'int main() { (void)(1 ? ({"abc";}) : ({42;})); }' | g++ -x c++ - -c`
Roger Pate
@Roger: thank you, i learned something new
sambowry
+1  A: 

In principle, yes:

if (A) B; else C

becomes

try {
  A ? throw TrueResult() : throw FalseResult();
  // or: throw A ? TrueResult() : FalseResult();
} catch (TrueResult) {
  B;
} catch (FalseResult) {
  C;
}

Compared to using procedures (which are more natural), this allows break, continue, return etc. It requires evaluation of A doesn't end with TrueResult/FalseResult but if you use those exceptions only to simulate if, it won't be a problem.

sdcvvc
+3  A: 

No, of course not. For reasons already mentioned, and more!

#include <cstdlib>
#include <iostream>

int main()
{
 if(int i = std::rand() % 2)
 {
  std::cout << i << " is odd" << std::endl;
 }
 else
 {
  std::cout << i << " is even" << std::endl;
 }
}

Check out where is is declared. It's not an often used technique, but it can be used in situations like COM where every call returns HRESULT which is (almost always) zero on success (S_OK), non-zero on failure, so you might write something like:

if(HRESULT hr = myInterface->myMethod())
{
 _com_raise_error(hr);
}

The ternary operator can't do anything analogous.

DrPizza