Reputation: 6386
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.
Upvotes: 1
Views: 148
Reputation: 61952
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).
Upvotes: 1
Reputation: 10958
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.
true
and false
in this example could also be variables of course, I simply used constant to make the example easier to understand.
Upvotes: 0
Reputation: 151604
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...
Upvotes: 2