4

I have a method in C# called SendEvent that returns a bool which represents if it was successful or not. I want to loop through a number of objects and call SendEvent on them all, and in the end, have a result variable that is a bool, that is true if all SendEvent calls succeeded, and false if at least one failed.

At first I did this:

bool result = true;
for (int i = 0; i < myObjects.Length; i++)
{
    result = result && myObjects[i].SendEvent();
}

But that will cause that the SendEvent will not be called on subsequent objects if one fails, as the right hand side of the && operator won't be executed if result is false.

So I turned it around, to:

bool result = true;
for (int i = 0; i < myObjects.Length; i++)
{
    result = myObjects[i].SendEvent() && result;
}

But I found that somewhat ugly. Can I use the bitwise &= operator to always execute the SendEvent call, and set the value of result, like this?

bool result = true;
for (int i = 0; i < myObjects.Length; i++)
{
    result &= myObjects[i].SendEvent();
}

How does the &= work on boolean values? Will it execute both sides of the operator? What will end up in the result variable?

Helena
  • 1,041
  • 2
  • 12
  • 24

2 Answers2

9

As you can read here, both & and && are defined for bools as "logical and", but && will short-circuit: in case the first operand is false the expression on the right will not be evaluated. Regardless what the outcome of the expression on the right is, the result of the && expression will remain false. This is usually a "performance hack" in the first place, but if the right expression has side-effects, could throw an exception, etc., it is something you have to take into account. The same happens for the || operator if the first operand is true.

So if you want to evaluate both sides first, you can indeed use:

result = result & myObjects[i].SendEvent();

or shorter:

result &= myObjects[i].SendEvent();

Background

As is written in the language specifications:

The operation

x && y  

corresponds to the operation

x & y  

except that if x is false, y is not evaluated, because the result of the AND operation is false no matter what the value of y is. This is known as "short-circuit" evaluation.

Note that there is no &&= operator (at least at the time I am writing this). This looks reasonable since usually with an ..= operator, you would expect that the operand is first evaluated and then some operation is done on the variable to the left. Of course it is all a matter of style and taste, but I would reason that a hypothetical &&= does not give "enough hints" that the right operand will not be called in all cases.

Community
  • 1
  • 1
Willem Van Onsem
  • 443,496
  • 30
  • 428
  • 555
6

As a LINQ lover, I would do it like:

var result = (myObjects.Count(obj => obj.SendEvent()) == myObjects.Length);

In case you want to break the loop on the first false value, it coud be:

var result = myObjects.All(obj => obj.SendEvent());
dotNET
  • 33,414
  • 24
  • 162
  • 251
  • @WillemVanOnsem my bad, missed that line – Sergey Berezovskiy Mar 22 '17 at 14:17
  • 2
    Hmm, personally I try to avoid using predicates that have side-effects in Linq... It can lead to surprising things if (for example) some code enumerates the result twice (of course, you should avoid enumerating `IEnumerable` things multiple times in general, but still) – Matthew Watson Mar 22 '17 at 14:25
  • @MatthewWatson: Trying to grasp what you said. Can u put a quick example plz? Also, how will that affect a regular `for` loop? – dotNET Mar 22 '17 at 14:27
  • @dotNET: I think here it does not matter, but what Matthew is probably trying to say is that if you have something like: `somelist.Where(x => SideEffect(x))` then the `.Where` will be evaluated lazily. As a result you don't know when the `SideEffect` will be called, this can resulting in unpredictable behavior. It can take days before the `SideEffect` is eventually called for some `x` and then the call might be outdated, etc. Usually it is always good practice to avoid too many side-effect functions anyway. – Willem Van Onsem Mar 22 '17 at 14:30
  • @WillemVanOnsem: Thanks a lot. I see the issue now. – dotNET Mar 22 '17 at 14:42