2

Does in c# all if statements were analysed before execution, so that in case an if statement can't be true (before proof all conditions) will be canceled?

My problem is, that i want to get rid of multiple if statements, becuase some methods in the if statement needs a long time to execute (which is wasted time if they were executed).

Here is a simple if statement (here it works). But how good is this on complex if statements?

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;

namespace IfTest
{
    class Program
    {
        static void Main(string[] args)
        {
            if (true || NeedALongTime())
            {
                Console.WriteLine("!");
            }

            Console.ReadLine();
        }

        private static bool NeedALongTime()
        {
            Thread.Sleep(10000);

            return true;
        }
    }
}
BendEg
  • 20,098
  • 17
  • 57
  • 131
  • 1
    No they're not all evaluated for boolean expressions with `&&` and `||` (Google about _short-circuit_). That's why you can write `if (obj != null && obj.Value == someValue)`. Moreover if expression can be determined and it's constant at compile-time then compiler itself _may_ optimize (in release mode) that code away (but you should also receive a warning for this). – Adriano Repetti Jan 07 '15 at 08:54
  • And as a general statement, the best way to deal with performance is to write clear, well thought out code and set performance *goals*. Then, you measure the performance of what you've written and, if its good enough, you just move on to the next task. You *don't* write well performing code by creating a list of thousands of "rules" about "I should write all `if` statements like *this*", etc. – Damien_The_Unbeliever Jan 07 '15 at 08:56
  • It already works this way, the entire if() statement is removed and only the call to Console.WriteLine() remains. Of course you'll never notice that it runs a nanosecond faster. Fifth bullet in [this post](http://stackoverflow.com/a/4045073/17034). – Hans Passant Jan 07 '15 at 09:17

2 Answers2

3

The evaluation model for the boolean operators && and || is well-defined. The second operand is only evaluated if the answer cannot be derived from the first operand.

This is called short-circuiting. This is guaranteed behavior.

This is not an optimization of the compiler or the JIT.

You can rely on this but in my mind it makes for brittle and error prone code to do so for performance reasons. It might not be apparent to future maintainers why the order of evaluation has to be this way although there seem to be no obvious dependencies. Maybe you can use Lazy<T> to get lazy evaluation?!

usr
  • 168,620
  • 35
  • 240
  • 369
  • @BendEg then, I'll elaborate: You can set up one Lazy for each expensive computation you might need to run. They can reference each other (so they form a DAG of dependencies). That way you can write your if statements and other computations to be maximally lazy automatically. – usr Jan 07 '15 at 09:15
1

The NeedALongTime method will never be called. C# will stop evaluating a logical expression as soon as it's able to determine the outcome.

This is called short-circuiting and isn't related to any sort of analysis. This is the way the language evaluates logical expressions. If you used a method returning true instead of the true value, short-circuiting would still work and NeedALongTime wouldn't be called.

Languages like C# and C++ use short-circuiting while others, like VB.NET don't.

You should be careful when using short-circuiting. While it's good practice to order the expression so that the most likely condition occurs first, it's very bad practice to inject short-circuiting flags in expressions just to improve performance in some scenarios.

It's better to use different if statements for such condition statements. The resulting IL code will be the same but the code will be much clearer.

If you need to check several conditions before executing the method, or have conditions for multiple heavy methods, it's better to bundle them at the start of your code, or even extract the condition check to a separate function. This way you avoid mixing up the guard conditions with the actual business logic

Panagiotis Kanavos
  • 120,703
  • 13
  • 188
  • 236
  • Thank you for your answer. One question to: `Languages like C# and C++ use short-circuiting while others, like VB.NET don't.`. I thought the .net framework do this job, not C#/VB.Net in general. – BendEg Jan 07 '15 at 09:00
  • 1
    No, each language uses its own semantics. You could say that the CPU does this job but this isn't true either. A boolean expression only has two arguments. A complex logical expression is a combination of boolean expressions evaluated in the order and semantics defined by the specific language. – Panagiotis Kanavos Jan 07 '15 at 09:10
  • 1
    I disagree with *You should be careful when using short-circuiting*. I don't care about other languages when I write `C#` code and in `C#` short-circuiting is a pretty way to combine executing logic into condition itself to avoid trees of `if`. It's very easy to follow, to example, `if(CheckA || CheckB && CheckC) DoSomething();`, where you know, what `CheckA` (will it be property setter code or method) will occurs always, but `CheckB` will occurs only if `CheckA` will fail, `CheckC` only if `CheckB` will not fail (but `CheckA`) and `DoSomething` call (and call logic) is not obscured. – Sinatr Jan 07 '15 at 09:35
  • I don't think you disagree. The question is about writing code like `if (CheckA || DoSomething()) { LogSomething();}`. I did write that the checks should be bundled together but the actual operations should be separate. I didn't write that you should take VB.NET into consideration or that you shouldn't use short-circuiting at all. – Panagiotis Kanavos Jan 07 '15 at 09:51
  • Thank you, only as an information, `NeedALongTime` doesn't do any operations. It just proof something. – BendEg Jan 07 '15 at 12:17