D Stanley's answer is correct; your error is in thinking of &
as being "bitwise" when applied to bool
. It is better to think of &
and &&
as being the eager and lazy versions of logical AND when applied to bool
.
Now here's a question that you didn't ask, but is actually the more interesting question:
Why is there a non-short-circuiting version of AND and OR for bool
in the first place? That is, why would you ever say exprX & exprY
instead of exprX && exprY
?
The bad reason is: expression exprY
might have a side effect that you want to always happen regardless of the value of exprX
. This is a bad reason because it's a questionable practice to use an expression both for its side effects and its value.
The good reason is: it can be faster to compute &
than &&
.
How is that possible? Surely if we can avoid computing the right hand side some of the time then we can always save time on average, right?
Wrong wrong wrong. z = x && y
will be generated as code that has the structure:
if x goto CONSEQUENCE
z = false
goto DONE
CONSEQUENCE: z = y
DONE:
That's a lot of instructions compared to simply computing x & y
and assigning the result to z
, and large code takes more time to load off disk, more time to jit compile, and uses up more space in the processor cache.
Moreover, those instructions contain a conditional branch and a non-conditional branch, increasing dramatically the number of basic blocks which the jitter must handle. (A "basic block" is a section of code with a clear start and finish such that if there are no exceptions, all the code in the basic block executes.) The jitter might choose to eschew certain optimizations when the number of basic blocks it has to analyze gets too large.
Worst of all, any conditional branch gives the CPU an opportunity for its branch predictor to make the wrong choice, which can have serious performance repercussions in some cases.
Now, this is not to say that you should never use &&
for bools; there's no program yet whose dramatic success in the marketplace is attributable to the use of this nano-optimization. I point it out merely because it is not entirely obvious why there should be a non-short-circuiting logical operator on bools at all.