views:

94

answers:

6

I often do this when necessary to prevent a null pointer exception:

// Example #1
if (cats != null && cats.Count > 0)
{
  // Do something
}

In #1, I've always just assumed that the cats != null needs to be first, because order of operations evaluate from left to right.

However, unlike example #1, now I want to do something if the object is null or if the Count is zero, therefore I'm using logical OR instead of AND:

// Example #2
if (table == null || table.Rows == null || table.Rows.Count <= 0)
{
  // Do something
}

Does the order of the logical comparisons matter? Or can I also reverse the order and get the same results, such as in Example #3?

// Example #3
if (table.Rows.Count <= 0 || table.Rows == null || table == null)
{
  // Do something
}

(btw, I realize I can rewrite #2 like below, but I think it's messy, and I'm still curious about the OR operators)

// Example #4
if (!(table != null && table.Rows != null && table.Rows.Count > 0))
{
  // Do something
}
A: 

Order matters. Its all about short circuiting. For ands, the first false it hits it stops evaluating, for ORs it stops as soon as it hits a true.

It will short circuit after the first evaulation and that is why you dont get the null pointer exception.

When you think about it think insert null for each object.

if (null== null || null.Rows == null || null.null.Count <= 0)
{
  // Do something
}

Then evaluate each boolean

if( true || null.Rows == null || null.null.Count <=0)

If you see true that means stop. If you hit a "null". statement you will crash.

Example to illustrate a crash

if (null.null.Count <= 0 || null.Rows == null || null== null)
{
  // CRASH... Do something
}
Nix
+1: thanks, but Jon Hanna is more clear to me.
JohnB
This is wrong, it's the exact opposite. For ANDs, the first **false** it hits will stop evaluating because the overall statement can't be true; for ORs it can stop as soon as **any** part is true.
Stephen P
yup, that was a little bit of a typo... fixed now.
Nix
+5  A: 

In the example you provide:

if (table == null || table.Rows == null || table.Rows.Count <= 0)
{
  // Do something
}

...neither table.Rows, nor table.Rows.Count, will be dereferenced if tables is null.

That's because, with C# logical operators, order of operations matter. C# logical operators are short-circuiting - they evaluate from left to right, and if any result causes the rest of the expression to be moot, the rest of the expression will not be evaluated.

Consider this code:

bool A()
{
    return false;
}

bool B()
{
    return true;
}

//...

if (A() && B())
{
    // do something
}

For an AND clause to be true, all elements must be true. However, A() returns false, and the runtime (or maybe the compiler here, in an optimization step, but let's not worry about that...) won't evaluate B() at all.

The same holds true for OR (||) expressions. If any element in the clause is true, evaluated left to right, the rest of the clause won't be executed.

Michael Petrotta
Side note: VB doesn't short-circuit operators like this is you use `And`. It will if you use `AndAlso`.
Jonathan Allen
+1: if you edit and give me only the bottom 6 lines of your answer (including the carriage return) I will mark you as the answer.
JohnB
@John: Thanks, but I'd prefer not to; I'm writing for future readers too. Mark whichever answer helped you the most.
Michael Petrotta
@Jonathan Allen: omg +100! I always wondered what the heck `AndAlso` was for! I despise VB :( But I'm using `AndAlso` instead of `And` in it from now on!
JohnB
@Michael: well, I respect your principles! But you should at least put the "answer" to my question at the top!
JohnB
@JohnB: let me see what I can do... ok, done.
Michael Petrotta
@JohnB: VB actually has a lot of nice stuff hidden in it, but you really have to learn it. If you just translate C# code verbatim then you will always feel like you using a butter knife as a screwdriver.
Jonathan Allen
Jon Hanna
A: 

Order does not matter.

Clarification:

The order you place the statements in the IF statement will not affect whether or not the IF statement is gone into...and thus the result.

As another poster pointed out, it will however affect which ones are evaluated, but this doesn't affect the bottom line AFAIK.

Edit @JonHanna

I guess I looked at this from the perspective that the OP stated he is checking for NPE's prior when required (see the first line of his post). So if his code doesn't produce runtime errors, then order means nothing. I can't imagine why anyone would code an IF statement with a thought process of "if this IF statement causes a NPE" then it won't get evaluated...

A null pointer exception affects the bottom line. Reverse the order in the first example in the question, and that's what you get.
Jon Hanna
A: 

The first construction is not the same as the second one. The first one is to use when you want to not do anything when the reference is null or Count is zero. The second construction would DO something when it is null or the count is zero... To make the second one the same as the first you would need to write:

 if (table == null || table.Rows == null || table.Rows.Count <= 0 || ) 
 {}
 else
 { 
  // Do something 
 } 

And order does matter, even in the second one as you wrote it, it would crash if table was null when it tried to evaluate table.Rows.

Charles Bretana
I think you misunderstood my goal. In the second "construction," I want to **DO** something when it is null or the count is zero.
JohnB
If that is the case then the first example is not doing that, it is doing something when the reference is NOT null. Or are the examples not supposed to represent the same task? If that's the case then the only thing wrong is that you need to reverse the order, because the order does matter, as others have also suggested...
Charles Bretana
Thank you very much for your help Charles. I'm sorry that my question was unclear to you; I have revised it to better illustrate what I mean. Others have already addressed my intended question. Thanks again.
JohnB
@JohnB, np, You are welcome, and very gracious !
Charles Bretana
+1  A: 

Yes, the short-circuiting happens in both cases, the only difference being that && stops if the LHS is false (because the overall expression must then be false) while || stops if the LHS is true (because the overall expression must be true).

The first two examples in your question are correct, the third will throw an exception if table or table.Rows are null.

Jon Hanna
+1: great clear answer, but I think Michael beat you.
JohnB
I think he did too. I added this because I thought I could put it clearer, but personally I'd give Michael the tick.
Jon Hanna
A: 

You should note that not all C# logical operators exhibit short-circuting behaviour (as was indicated above).

You are using the Conditional-AND operator (&&) and that does short-circuit. However the AND (&) operator is exactly the same as the Conditional-AND without the short-circuit.

The same is true for the OR and Conditional-OR operators.

For Example:

//This will throw if cats is null, whatever order.

if (cats != null & cats.Count > 0){ }

//This will not. Due to short-circuting.

if (cats != null && cats.Count > 0){ }

jnielsen