Does combining short-circuiting operators with regular operators change the result of the expression?

StackOverflow https://stackoverflow.com/questions/14671958

Pergunta

I've always believed that using conditional boolean operators (a.k.a. short-circuiting) in stead of regular boolean operators doesn't affect the outcome of an expression.

var result = true | false & false;

has the same result as

var result = true || false && false

Both expressions result in true.

But what if I would mix regular and conditional operators?

var result1 = true || false & false;
var result2 = true | false && false;

What would you expect? I would expect these to still return true. But that isn't the case. Result2 will be false!

I know this is because of the operator precedence. The precedence order is & | && ||. This seems counter intuitive to me. I'd expect an order of & && | ||, in which case all results would be the same (I think).

So I guess my real question isn't if short-circuiting can change the result. The question is why the order of precedence is such that short-circuiting can change the result.

Foi útil?

Solução

var result2 = true | false && false;

Is calculated as:

var result2 = (true | false) && false;

Because | comes before &&. Now (true | false) evaluates to true, and true && false is false.

As for the why, see this question:

The && and || operators were added later for their "short-circuiting" behavior. Dennis Ritchie admits in retrospect that the precedence of the bitwise operators should have been changed when the logical operators were added. But with several hundred kilobytes of C source code in existence at that point and an installed base of three computers, Dennis thought it would be too big of a change in the C language...

Outras dicas

The precedence of the operators in question seems to be copied directly from the precedence in the C (and C++) programming language.

Now in C, they don't use distinct types for integers and booleans. For example they could write:

if (i | j && x > 0)      // cf. the result2 of your question

and this should mean "the integers i and j bitwise or'ed gives something nonzero AND the number x is positive". So | and & are supposed to be mostly used when the operands are thought of as integers (many-bit numbers), and || and && are supposed to be mostly used when the operands are thought of as booleans.

So it might seem natural in C that | binds more strictly than &&.

In C# we have a higher degree of type safety, and there are no conversions from Int32 to Boolean or from Boolean to Int32. Therefore it is no longer possible to "mix" things, and the precedence no longer feels natural.

I guess in theory in C#, one could make the operator

public static bool operator |(bool b, bool c)

have a different precedence than the operator

public static int operator |(int i, int j)

but it wouldn't really make things better?

I think it's very rare that people use boolean non-short-circuit operators like | and short-circuit operators like && in the same expression, but when they do, they should either be very careful about precedence, or just put the parenthesis () there (it will also make the intention more clear).

The & and | operators evaluate both arguments (which could involve calling a method) and then return the result of the and- or or-operation.

The && and || operators only evaluate their arguments to the point where the final result is determined completely.

For example: true | SomeMethod() and false & SomeMethod() calls the SomeMethod() function true || SomeMethod() and false && SomeMethod() don't.

trueand false in this example could also be variables of course, I simply used constant to make the example easier to understand.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top