1

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.

Community
  • 1
  • 1
comecme
  • 6,086
  • 10
  • 39
  • 67
  • Short circuiting can definitely change the side-effects (i.e. if the boolean expressions are methods), and it would therefore make sense to make a distinctions. – antonijn Feb 03 '13 at 11:30
  • @Antonijn: do you mean it can change the side-effects? – comecme Feb 03 '13 at 11:32
  • I'm sorry, I should have been clearer. – antonijn Feb 03 '13 at 11:35
  • 1
    The answer is boring, it is because it inherited the precedence and associativity rules from C, like all curly brace languages. Make it interesting by playing the role of the language designer and propose an alternative. You only have a few choices, precedence can be opposite or equal. If equal then associativity matters, possibly what you overlooked. – Hans Passant Feb 03 '13 at 15:56

3 Answers3

2
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...

Community
  • 1
  • 1
CodeCaster
  • 147,647
  • 23
  • 218
  • 272
  • 1
    As far as I know the & and | operators are meant for bitwise operations, they are not what you can in your first sentence "regular boolean operators". Since a bool can represent a single bit it works for them as well. The && and || operators are logical operators for truth values. – Dirk Feb 03 '13 at 11:40
  • No doubt the designers of C# simply copied the precedence known already from C and C++. But note that the thread you're referring, is advocating for moving the operators `&` and `|` _further_ away from `&&` and `||`, "through" the `==` and `!=` operators, so that `&` and `|` come first, then come `==` and `!=`, and only then come `&&` and `||`. That would be less confusing in C because they use the same type for integers and booleans. Thus when they say `if (i & j == 0)` it compiles fine (wouldn't compile in C# with `int`), but is certainly different from the intended `if ((i & j) == 0)`. – Jeppe Stig Nielsen Feb 03 '13 at 20:55
  • I think it is a good idea to only use `&` and `|` when I need bitwise and/or. From now on, for boolean and/or I'll always use `&&` and `||`. – comecme Feb 04 '13 at 17:18
1

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).

Jeppe Stig Nielsen
  • 60,409
  • 11
  • 110
  • 181
0

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.

Dirk
  • 10,668
  • 2
  • 35
  • 49