&= for bools?

P

proxyuser

I see the equivalent of this in some code.

bool a, b, c;
a &= b;

Is that correct? I would have thought it would be
a &&= b;

Of course I'm not saying &&= is an operator, but

a = a && b;
 
Z

z.sessions

I see the equivalent of this in some code.

bool a, b, c;
a &= b;

Is that correct?  I would have thought it would be
a &&= b;

Of course I'm not saying &&= is an operator, but

a = a && b;

According to the help library, &= is a valid assignment operator, but
&&= is not listed.
 
J

Jeff Johnson

I see the equivalent of this in some code.

bool a, b, c;
a &= b;

Is that correct? I would have thought it would be
a &&= b;

Of course I'm not saying &&= is an operator, but

a = a && b;

I guess what's happening behind the scenes is that the bools are being
treated as the numbers they actually are and their bits are being AND'ed. Of
course, since there are only two possible underlying values for a bool,
AND'ing them will either result in the True value if they're both True or
the False value otherwise, so the ultimate result will be the same as
applying the && operator.
 
G

Geoffrey Summerhayes

According to the help library, &= is a valid assignment operator, but
&&= is not listed.

More to the point (from the entry):

"The & operator performs a bitwise logical AND operation on integral
operands and logical AND on bool operands."
 
P

proxyuser

Geoffrey Summerhayes said:
More to the point (from the entry):

"The & operator performs a bitwise logical AND operation on integral
operands and logical AND on bool operands."

Ah, I missed that, thanks. Does this beg the question "Why is the &&
operator needed then?" ?
 
Z

z.sessions

Ah, I missed that, thanks.  Does this beg the question "Why is the &&
operator needed then?" ?

It's not. If a is true, b does not get evaluated with &&, so it can
save time.

&& is mainly used in cases when you need to check an object's property
and you are not sure the object has been instantiated yet, as in:

if ((obj != null) && (obj.foo == "ABC"))
 
A

andy.johnstone

Ah, I missed that, thanks.  Does this beg the question "Why is the &&
operator needed then?" ?

&& is a logical operator, and & is the bitwise operator. The
expression on each side of && MUST evaluate to a boolean. & can be
used with other number types.
 
P

Pavel Minaev

&& is a logical operator, and & is the bitwise operator.  The
expression on each side of && MUST evaluate to a boolean.  & can be
used with other number types.

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

Pavel Minaev

Ah, I missed that, thanks.  Does this beg the question "Why is the &&
operator needed then?" ?

&& and || are short-circuiting (do not evaluate 2nd operator if the
result of expression is evident from the first one). & and | aren't.
Sometimes, when you have side-effects in a second operand, you care
about the difference, though in practice it is so rare that doing so
is potentially very confusing. VB has a similar distinction between
And/Or and AndAlso/OrElse.
 
P

proxyuser

It's not. If a is true, b does not get evaluated with &&, so it can
save time.

&& is mainly used in cases when you need to check an object's property
and you are not sure the object has been instantiated yet, as in:

if ((obj != null) && (obj.foo == "ABC"))

I assume you meant to write "If a is false...", right? I wonder why this
same optimization couldn't be implemented for &.
 
P

proxyuser

Pavel Minaev said:
&& and || are short-circuiting (do not evaluate 2nd operator if the
result of expression is evident from the first one). & and | aren't.
Sometimes, when you have side-effects in a second operand, you care
about the difference, though in practice it is so rare that doing so
is potentially very confusing.

I see, thanks.
 
G

Göran Andersson

proxyuser said:
I see the equivalent of this in some code.

bool a, b, c;
a &= b;

Is that correct? I would have thought it would be
a &&= b;

Of course I'm not saying &&= is an operator, but

a = a && b;

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;

That means that a short circuit assignment operator would actually do
more work than the regular assignment operator in some cases.

If you know that there is a lot of work to evalue the operand, you can
just slap an if in front of the assignment operator.
 
A

Andrew Faust

&& and || are short-circuiting (do not evaluate 2nd operator if the
result of expression is evident from the first one). & and | aren't.
Sometimes, when you have side-effects in a second operand, you care
about the difference, though in practice it is so rare that doing so
is potentially very confusing. VB has a similar distinction between
And/Or and AndAlso/OrElse.

I don't find it rare or confusing. I use lazy evaluation quite often. Some
examples:

if (!String.IsNullOrEmpty(myString) && myString.Length == 5) //if myString
were null the length check would throw an exception.

if (File.Exists(...) || DownloadFile(...)) //Useful for caching. If file is
available or it's sucessfully downloaded proceed.

I admit that if you aren't careful things can get confusing, however, that
statement applies to virtually any language feature.

Andrew Faust
 
P

Pavel Minaev

I don't find it rare or confusing. I use lazy evaluation quite often. Some
examples:

if (!String.IsNullOrEmpty(myString) && myString.Length == 5) //if myString
were null the length check would throw an exception.

if (File.Exists(...) || DownloadFile(...)) //Useful for caching. If file is
available or it's sucessfully downloaded proceed.

I meant it the other way around. Virtually always, you _want_ short
circuiting, which is why many languages out there don't even have non-
short-circuiting boolean operators. To that end, I'm saying that using
a non-short-circuiting operator because you need to rely on a side
effect is a second expression is something that occurs so rarely that
it may confuse a typical reader of the code.
 
P

Pavel Minaev

For an assigment operator short circuiting is not really useful. The &&=
operator would be the equivalent of:

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.

How so? An expansion of the non-short-circuiting operator also have to
do the same thing (i.e. check the value of "a" before assigning a new
one), because that's just how logical AND and OR work. The only
difference would be that a short-circuiting form would not evaluate b
if it's not needed.
 
G

Göran Andersson

Pavel said:
How so? An expansion of the non-short-circuiting operator also have to
do the same thing (i.e. check the value of "a" before assigning a new
one), because that's just how logical AND and OR work. The only
difference would be that a short-circuiting form would not evaluate b
if it's not needed.

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

A short-circuiting operator would have to make a test on the value from
a, then make a conditional jump depending on the result:

movzx eax, byte ptr [rsp+20h]
test eax, eax
je .skip
movzx ecx, bytr ptr [rps+21h]
and eax, ecx
mov byte ptr [rsp+20h], al
..skip
 
P

Pavel Minaev

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

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

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

Göran Andersson

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

Pavel Minaev

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

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.
 

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