&= for bools?

A

andy.johnstone

Please read the thread to which you're responding before doing that.
As noted by Geoffrey, in C# what you say is wrong - operators & and |
are Boolean and not bitwise when applied to bool operands (and yes,
they can be used with bool).

So your glass is half empty, and mine is half full? If you're only
dealing with one bit (which is what a bool represents), it's a bitwise
AND.
 
P

Pavel Minaev

So your glass is half empty, and mine is half full?  If you're only
dealing with one bit (which is what a bool represents), it's a bitwise
AND.

Bitwise operators work directly on in-memory bit representation of
values, not on their logical values (consider how it works for
negative signed integers to see what I mean). On the other hand, C#
does not prescribe any specific bit representation for bools, and in
fact does not even consider bool an integral type (it can't be
converted to int, even explicitly, so there's no true==1 false==0
equivalence, unlike C++).

In any case, rather than argue about wording, I suggest that we just
defer to what the language spec says, which is this:

"7.10.3. Boolean Logical Operators

There are three predefined boolean logical operators:
bool operator &(bool x, bool y);

bool operator |(bool x, bool y);

bool operator ^(bool x, bool y);

The result of x & y is true if both x and y are true. Otherwise, the
result is false.

The result of x | y is true if either x or y is true. Otherwise, the
result is false.

The result of x ^ y is true if x is true and y is false, or if x is
false and y is true. Otherwise, the result is false. When the operands
are of type bool, the ^ operator computes the same result as the !=
operator."

Note that nowhere the word "bit" is mentioned. In contrast, the same
operators applied to values of integral types are defined as:

"The & operator computes the bitwise logical AND of the two
operands, the | operator computes the bitwise logical OR of the two
operands, and the ^ operator computes the bitwise logical exclusive OR
of the two operands."

It's also worth remembering about the existence of & and | operators
on nullable bools, which are most definitely not "bitwise", neither in
semantics, nor on bit representation level (unless you're willing to
argue for "nullable bits", which would be an interesting concept).
 
G

Göran Andersson

Pavel said:
Pavel said:
No, the non-short-circuiting operator doesn't check the vale of a before
doing the operattion.
This code:
a &= b;
compiles into:
movzx eax, byte ptr [rsp+20h]
movzx ecx, bytr ptr [rps+21h]
and eax, ecx
mov byte ptr [rsp+20h], al
I was assuming that "a" and "b" are placeholders for arbitrary
expressions, not just variables. I see that it used the AND operator
here - but I doubt whether it will do the same in e.g. a statement
such as:
foo.Bar.Baz &= (x > y);
Yes, it does it the same way. There is more code to get the location of
foo.Bar.Baz and to evaluate the expression x > y, but the code for the
&= operation is still an and operation:

; get foo.Bar
mov rax,qword ptr [rsp+30h]
cmp byte ptr [rax],0
mov rcx,qword ptr [rsp+30h]
call FFFFFFFFFFEC96D0
mov qword ptr [rsp+40h],rax

; get Baz
mov rax,qword ptr [rsp+40h]
movzx edx,byte ptr [rax+8]

; evaluate x > y
xor ecx,ecx
mov eax,dword ptr [rsp+28h]
cmp dword ptr [rsp+24h],eax
setg cl
mov dword ptr [rsp+48h],ecx

; &=
mov ecx,edx
and ecx,dword ptr [rsp+48h]

; set Baz
mov rax,qword ptr [rsp+40h]
mov byte ptr [rax+8],cl
I'd rather expect it to stick to conditional jumps here (since it'll
have to do CMP either way, might as well jump right then, instead of
doing SET/AND).
Nope, no jumps. :)
By the way, the above disassembly is from the x64 JIT, right? Have you
tried it on x86? the difference between implementations can be very
drastic at times.
Good point. Yes, it was x64 code. The x86 code looks like this:

mov eax, dword ptr [ebp-28h]
and eax, dword ptr [ebp-2Ch]
and eax, 0ffh
mov dword ptr [ebp-28h]

It reads and writes the bool values as dwords instead of bytes, but
other than that it's pretty much the same.

Certainly very interesting. Another question, and I realise it may be
a dumb one, but did you make sure that JIT optimization wasn't
disabled because the debugger is attached? (as you surely know, the
default JIT behavior is to disable optimizations when running under
debugger).

Yes. I actually had to add a few variables to get some neutral code, as
the compiler kept putting the variables in registers instead of on the
stack. :)
In any case, getting back to why we started talking about it - a short-
circuiting &&= would be useful in precisely the same situation where a
short-circuiting && is useful today - when the second argument is
potentially too expensive to be evaluated. In practice, more often
than not it's a reasonable default - if the right side of && is a
local variable, then the compiler can do whatever it wants (e.g. AND),
since "evaluating" the variable doesn't have any visible side effects
as far as programmer is concerned; and if there are any potential side
effects (as is the case for field access and method calls), then it is
most likely that evaluating the right side will take more time then
doing a TEST/JE on the left side to short-circuit. This all equally
applies to &&=, naturally, so it would be reasonable to have it in the
language, and reasonable to use it by default for most cases.

Well, frankly the operator isn't that useful anyhow. In any situation
where the performance would make any difference, i.e. in a loop, you
would skip out of the loop at the earliest possible moment, so you would
rather just set the variable than accumulating conditions in it:

bool isSmall = true;
foreach (string s in strings) {
if (s.Length > 20) {
isSmall = false;
break;
}
}

rather than:

bool isSmall = true;
foreach (string s in strings) {
isSmall &= s.Length <= 20;
}

I think that one reason that the &&= operator isn't included in the
language is that it produces less efficient code than the &= in some
cases, which isn't really what you would expect from a short circuit
operator. Just like we use the && rather than the & operator, we would
use the &&= operator rather than the &= operator without considering if
the condition is expensive enough to evaluate, that the short circuit
would be more efficient.
 
P

Pavel Minaev

I think that one reason that the &&= operator isn't included in the
language is that it produces less efficient code than the &= in some
cases, which isn't really what you would expect from a short circuit
operator.Just like we use the && rather than the & operator, we would
use the &&= operator rather than the &= operator without considering if
the condition is expensive enough to evaluate, that the short circuit
would be more efficient.

Yes, but we already do that with && anyway, and all your arguments
about efficiency or inefficiency of short-circuiting that apply to &&=
also apply to &&.

Besides, as I've pointed out, for vast majority of cases the condition
is either expensive enough, or the compiler can determine that it is
safe to optimize away the short-circuiting.
 
G

Göran Andersson

Pavel said:
Yes, but we already do that with && anyway,

No, we don't.
and all your arguments
about efficiency or inefficiency of short-circuiting that apply to &&=
also apply to &&.

No, it doesn't.

I have tried to show you the difference, but if you don't want to try to
understand, I don't see any point.
 
A

andy.johnstone

Bitwise operators work directly on in-memory bit representation of
values, not on their logical values (consider how it works for
negative signed integers to see what I mean). On the other hand, C#
does not prescribe any specific bit representation for bools, and in
fact does not even consider bool an integral type (it can't be
converted to int, even explicitly, so there's no true==1 false==0
equivalence, unlike C++).

Except that if you read the documentation, & is an operator which any
type may define as it sees fit. So I don't think that matches that
"bitwise operators work directly on in-membory bit representations."
Yes, System.Boolean is a type just like any other type, and it defines
& and |, just like many other types. Yet it still represents a value
which can have one of two possible values... 0 or 1, true or false.
So despite what any documentation says, you can still think of it as a
bitwise operator. It just operates on one bit.

I'd also like to point out that if you use Reflector, System.Boolean
does in fact define a True value as Int32 = 1, and False as an Int32 =
0. I don't see anywhere it's used... but that doesn't mean the
framework isn't special casing it, like it does some other types (I
think there's a "special" type in Wpf that handled separately by the
compiler). Also, if you do a Convert.ToInt32( true ), you get back
1.

So yes, I think you're just arguing semantics. And while the
documentation is picky.. computers only work with two discrete values
at the end of the day... 0 or 1. The framework is abstracting things
so we need not worry about which bits will represent true and false...
but that's just because it's done for us.

As to your point on System.Nullable<T>.. it also implements & and |
for itself. No type has a default implemenation of & or |.. but
System.Nullable<T> has logic that says if either argument is null, it
returns null. Otherwise it trys to use the & or | operator, and if
it's not defined on the type,you'll get a compiler error. Go try it
yourself.
 
B

Ben Voigt [C++ MVP]

Göran Andersson said:
The && operator does a short circuit evaluation, which means that if
the first operand is false the second operand doesn't need to be
evaluated.
For an assigment operator short circuiting is not really useful. The
&&= operator would be the equivalent of:

if (a) a &= b;

Actually, it'd be

if (a) a = b;
That means that a short circuit assignment operator would actually do
more work than the regular assignment operator in some cases.

A very little more. And potentially a whole lot less. And depending on the
probability of a being true and whether b is in cache, even when the RHS is
a simple variable, short-circuiting may be faster.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top