Boolean Or containing Ternary conditional operation doesn't get short-circuited
Asked Answered
D

4

-1

In general, the short circuit or operator || ignores the right side of the or if the left side evaluates to true. Apparently, we've found an exception to this.

Check out the following:

if (foo == null || bar != true ? foo.Count == 0 : true)
{

}

This code throws a null reference exception on the command foo.Count because foo is null. And naturally, the boolean logic allows for this. But, if foo is null you would expect that the or would short circuit and not even evaluate the right side of the expression, but it still does, and it throws an exception.

Is this a bug in my code or in the C# compiler? Is there a part of the C# specification that handles this case?

Daisey answered 9/11, 2012 at 17:37 Comment(6)
It might be worthwhile to add some code to setup the objects (foo and bar) as you are using them.Towland
@Daisey What exception is thrown?Simsar
@GeorgeStocker This code throws a null reference exception on the command foo.CountLigulate
Please avoid "begging the bug" in titles. Chances are high it's not the compiler/language/library.Shoemaker
This really is a messy way of laying out your conditional statements. You should be using parenthetical separations to explicitly describe what the order of operations is intended to be - even if you want the default behavior.Theisen
I would re-write that as if(foo == null || bar || !foo.Any())). I feel that it's much easier to read than your solution, even after adding more parenthesis to have it run as you intended.Trunnion
P
17

That's because your statement isn't being evaluated as you expect.

You need some extra parenthesis:

if(foo == null || (bar != true ? foo.Count == 0 : true))

The way it's written now is equivalent to (due to operator precedence):

if((foo == null || bar != true) ? foo.Count == 0 : true)    
Pander answered 9/11, 2012 at 17:40 Comment(0)
T
11

No, it works correctly, refer to operator precedence. || will be evaluated before ?:

So it firstly evaluates foo == null || bar != true and then ? foo.Count == 0 : true, so it's more like:

if ((foo == null || bar != true) ? foo.Count == 0 : true)
{

}

If you want to use short-circut here then it should be:

if (foo == null || (bar != true ? foo.Count == 0 : true))
{

}
Transect answered 9/11, 2012 at 17:40 Comment(0)
D
3

Imagine parentheses around the condition you're checking:

if ((foo == null || bar != true) ? foo.Count == 0 : true)
{

}

Thus, if foo is null, you're attempting to read foo.Count, which will naturally result in a NullReferenceException.

Disruptive answered 9/11, 2012 at 17:41 Comment(0)
I
2

According to Operator precedence and associativity conditional operator ?: has lowest priority. Thus it will be executed last. Like this:

(foo == null || bar != true) ? foo.Count == 0 : true
Incomprehensive answered 9/11, 2012 at 17:46 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.