17

I have an expression like this:

EqualByComparer comparer;
if (ListEqualByComparer.TryGetOrCreate(x, y, out comparer) ||
    EnumerableEqualByComparer.TryGetOrCreate(x, y, out comparer))
{
    return comparer.Equals(x, y, compareItem, settings, referencePairs);
}

Will ListEqualByComparer.TryGetOrCreate always be called before EnumerableEqualByComparer.TryGetOrCreate?

Kainix
  • 1,186
  • 3
  • 21
  • 33
Johan Larsson
  • 17,112
  • 9
  • 74
  • 88
  • 6
    Yes and if it returns true, EnumerableEqualByComparer.TryGetOrCreate(x, y, out comparer) will not be called (short circuit evalution) – vc 74 Apr 06 '16 at 10:13
  • See also [Operator ||](https://msdn.microsoft.com/library/6373h346.aspx) - in `if (x || y)` it is guaranteed that `x` will be checked (first). If `x` is `true`, `y` will *not* be evaluated at all. – Corak Apr 06 '16 at 10:14
  • I believe so, this exact context being the reason for it. The code is compiled this way to save memory, as if the first condition is true, it will not have to evaluate the second condition – Alfie Goodacre Apr 06 '16 at 10:14
  • Sorry about the dupe, I did a search but failed. – Johan Larsson Apr 06 '16 at 10:16
  • 2
    Just to note, the fact the sequence is fixed and the second condition is only called if necessary is often both important and useful. I often write conditions such as `if (foo == null || foo.bar())` – Stuart Whitehouse Apr 06 '16 at 10:17
  • @StuartWhitehouse Indeed, i also use this when i get a collection to check if it is null or if it has any objects in int if ( collection == null || !collection.Any() ) – Nikola.Lukovic Apr 06 '16 at 10:19

4 Answers4

29

Will ListEqualByComparer.TryGetOrCreate always be called before EnumerableEqualByComparer.TryGetOrCreate?

Yes, and as || is short-circuiting, the second call will only be made if the first call returns false.

From the C# 5 specification, section 7.12.1:

When the operands of && or || are of type bool, or when the operands are of types that do not define an applicable operator & or operator |, but do define implicit conversions to bool, the operation is processed as follows:

[...]

The operation x || y is evaluated as x ? true : y. In other words, x is first evaluated and converted to type bool. Then, if x is true, the result of the operation is true. Otherwise, y is evaluated and converted to type bool, and this becomes the result of the operation.

Community
  • 1
  • 1
Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • Thanks, I tried to find it in the language spec but failed. – Johan Larsson Apr 06 '16 at 10:14
  • 2
    @JohanLarsson: Have added a spec reference. – Jon Skeet Apr 06 '16 at 10:18
  • A question: As these are function calls, does it mean that function calls are also called from left to right, one-by-one or could it be that all functions would be called in some order to extract the operands before evaluating them? – Veksi Apr 06 '16 at 10:26
  • @Veksi: I'm not sure what you mean in this case. Evaluating the operand means calling the method here... you can't "evaluate the left operand" without calling the method, and the language is guaranteeing that the right operand won't be evaluated until the left operand is evaluated. Generally speaking the *does* guarantee left-to-right evaluation, but that would be more important for something like `Foo(Bar(), Baz())` – Jon Skeet Apr 06 '16 at 10:29
  • That was the question, I suppose. In C++ (I believe), if one has a conditioanl such as `if(func1() && func2() && func3()`, I believe it is implementation defined if all the functions will executed before evaluating the conditional in all the cases. That is, not just calling functions one-by-one from left to right. Link: http://cpptruths.blogspot.fi/2014/09/short-circuiting-overloaded-and-using.html, http://stackoverflow.com/questions/628526/is-short-circuiting-boolean-operators-mandated-in-c-c-and-evaluation-order. – Veksi Apr 06 '16 at 10:40
  • @Veksi: Well, that looks like it involves operator overloading as well. That's a slightly different matter. Note that the C# spec here is explicitly talking about situations where the operands are of type `bool`, or convertible to `bool` without also overloading `|` or `&`. – Jon Skeet Apr 06 '16 at 10:48
  • 2
    @Veksi C++ has the same rule as C# when dealing with the built in && / II, but it does *not* offer the same guarantee when `operator &&` is overloaded (which is why you are *strongly* recommended not to overload `operator &&`). OTOH given `foo( bar(), baz() )`, I am pretty sure that C# guarantees `bar` will be called before `baz`, but C++ does not. – Martin Bonner supports Monica Apr 06 '16 at 12:05
  • I guess it's worth noting that even though `Foo` is strictly left most it will still be called last. – Aswan Apr 07 '16 at 08:30
4

Yes - details are in the documentation.

The second condition is only evaluated if the first is false

Stuart Whitehouse
  • 1,421
  • 18
  • 30
4

From C# Reference (link):

The conditional-OR operator (||) performs a logical-OR of its bool operands. If the first operand evaluates to true, the second operand isn't evaluated. If the first operand evaluates to false, the second operator determines whether the OR expression as a whole evaluates to true or false.

Nikola.Lukovic
  • 1,256
  • 1
  • 16
  • 33
3

Yes, the order is guaranteed. MSDN states:

Logical operators also guarantee evaluation of their operands from left to right. However, they evaluate the smallest number of operands needed to determine the result of the expression. This is called "short-circuit" evaluation. Thus, some operands of the expression may not be evaluated.