short-circuit evaluation and assignment operators

A

Anthony Paul

Hello everyone,

I have the following code for testing my expression evaluator (I know
the code doesn't make sense, but it doesn't have to for the purposes
of this test) :

int Z = 5;
int e = Z || Z <<= Z;

My evaluator first evaluates Z, sees that it's true, and doesn't
evaluate the Z <<= Z part. So far so good. Now if I set Z = 0, it
would check Z, find it to be false, and then evaluate Z <<= Z and find
that false as well.

When I test the same code on either gcc or Visual Studio's C++
compiler, I get the "error: lvalue required as left operand of
assignment" error message during compilation. This would make sense if
Z || Z was evaluated first, and then it tried to apply Z <<= Z to the
result of that evaluation, but that can't be now can it? The short-
circuit evaluator clearly separates the expression into two camps :

Camp A : Z
||
Camp B : Z <<= Z

The above should clearly not produce the lvalue required error
message; Z IS an lvalue.


And yet the only possible way I can explain its reasoning is if it
were evaluating the expression as follows :

Camp A : Z || Z
Camp B : (result of Z || Z) <<= Z

But if that's the case, how could it possibly do short-circuit
evaluation?

Strange...

Warm regards,

Anthony
 
P

Peter Nilsson

Anthony said:
int Z = 5;
int e = Z || Z <<= Z;
When I test the same code on either gcc or Visual Studio's C++
compiler, I get the "error: lvalue required as left operand of
assignment" error message during compilation. This would
make sense if Z || Z was evaluated first,

It's a matter of parsing, not evaluation. Whilst Bitwise Shift
Operators
have higher precedence than Logical OR, Assignment operators
have a lower precedence.
... the only possible way I can explain its reasoning is if it
were evaluating the expression as follows :

Camp A : Z || Z
Camp B : (result of Z || Z) <<= Z

But if that's the case, how could it possibly do short-circuit
evaluation?

It can't. Write it as...

e = Z || (Z <<= Z);
 
L

luserXtrog

Hello everyone,

I have the following code for testing my expression evaluator (I know
the code doesn't make sense, but it doesn't have to for the purposes
of this test) :

int Z = 5;
int e = Z || Z <<= Z;

My evaluator first evaluates Z, sees that it's true, and doesn't
evaluate the Z <<= Z part. So far so good. Now if I set Z = 0, it
would check Z, find it to be false, and then evaluate Z <<= Z and find
that false as well.

When I test the same code on either gcc or Visual Studio's C++
compiler, I get the "error: lvalue required as left operand of
assignment" error message during compilation. This would make sense if
Z || Z was evaluated first, and then it tried to apply Z <<= Z to the
result of that evaluation, but that can't be now can it? The short-
circuit evaluator clearly separates the expression into two camps :

Camp A : Z
||
Camp B : Z <<= Z

The above should clearly not produce the lvalue required error
message; Z IS an lvalue.

And yet the only possible way I can explain its reasoning is if it
were evaluating the expression as follows :

Camp A : Z || Z
Camp B : (result of Z || Z) <<= Z

But if that's the case, how could it possibly do short-circuit
evaluation?

Strange...

Warm regards,

Assignments have lower precedence that logical operators.
This includes <<=. So the expression is parsed like your
second example. Like this:

e = ((Z || Z) <<= Z);

Now if the first Z is non-zero, it most certainly could avoid
evaluating the second Z. But the result of the logical operator
is not something that can be stored into.

You'll need explicit parens to explain this to the compiler.
The default rules interpret your expression as nonsense.
You could try:

e = (Z || (Z <<= Z));

But, of course, since the right hand size is short-circuited
unless Z == 0, what's the sense in rotating 0 zero times?
 
A

Anthony Paul

Hey guys,

Thanks for replying!

I see both of your points, and I think I understand now but I want to
clarify. Are you guys saying that whether short-circuit evaluation is
performed depends on precedence? If so, I get what you're saying.

To make sure I got this straight, the following :

Z || Z <<= Z

is evaluated as as

(Z || Z) <<= Z

and that's because the <<= operator has lower precedence. I imagine
that the short-circuit happens between the two Z's now, it evaluates
the first Z and finds it to be true (1) and doesn't evaluate the
second Z. It then does 1 <<= Z which is obviously an error. Got it.

Now in the case of :

Z || Z / 0

This compiles fine and evaluates to a 1. I would imagine that it is
evaluating this as :

Z || (Z / 0)

because the division operator has higher precedence. Now the short-
circuit happens completely different from the first example.... it's
now between the Z and the (Z / 0). Since the first Z evaluates to true
(1) it doesn't bother doing the rest.

If what I just said makes sense, then I understand now and I thank you
both! If not, then God help me! :p

Regards,

Anthony
 
B

Barry Schwarz

Hey guys,

Thanks for replying!

I see both of your points, and I think I understand now but I want to
clarify. Are you guys saying that whether short-circuit evaluation is
performed depends on precedence? If so, I get what you're saying.

No, short circuit evaluation does not depend of precedence. The short
circuit operators always perform short circuit evaluations.

What depends on precedence is which parts of the expression are the
actual operands of the || operator. You thought one operand was Z and
the other was Z<<=Z. Due to the precedence, the left operand was the
first Z and the right operand was the second Z.

There is no language problem with this. The problem occurs because
the result of Z||Z was used as the left operand of the <<= operator.

You got it right below.
 
G

gw7rib

Hey guys,

Thanks for replying!

I see both of your points, and I think I understand now but I want to
clarify. Are you guys saying that whether short-circuit evaluation is
performed depends on precedence? If so, I get what you're saying.

Barry Schwarz has commented on this.
To make sure I got this straight, the following :

Z || Z <<= Z

is evaluated as as

(Z || Z) <<= Z

and that's because the <<= operator has lower precedence. I imagine
that the short-circuit happens between the two Z's now, it evaluates
the first Z and finds it to be true (1) and doesn't evaluate the
second Z. It then does 1 <<= Z which is obviously an error. Got it.

Now in the case of :

Z || Z / 0

This compiles fine and evaluates to a 1. I would imagine that it is
evaluating this as :

Z || (Z / 0)

because the division operator has higher precedence. Now the short-
circuit happens completely different from the first example.... it's
now between the Z and the (Z / 0). Since the first Z evaluates to true
(1) it doesn't bother doing the rest.

Yes, these examples look fine.

Part of the problem is that computing is not the same as maths,
despite using similar terms. For instance, in maths, if you do:

x = 3 + 4 * 5

then to say "the addition uses the result of the multiplication" is
much the same thing as saying "you do the multiplication first".
However, these are slightly different concepts in computing. The
question of which operators operate on which values is called
precedence (unless you're very pedantic). The question of which
calculation is done when is called order of execution.

Here's a particularly tricky example:

x = y || (4+5);

In this case, the brackets give the addition a higher precedence
(though they're not strictly needed as + has a higher precedence than
|| anyway). So the values that || acts on are, on the one hand, y, and
on the other hand, 4+5. That's precedence. BUT, || works by checking
the first value and only evaluating the second value if needed - so
here, if y is not zero, 4 and 5 aren't added at all. So || starts
operating *before* the addition is carried out.

Once you follow that, everything else will be a walk in the park...

Hope that helps.
Paul.
 

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

Members online

Forum statistics

Threads
473,733
Messages
2,569,439
Members
44,829
Latest member
PIXThurman

Latest Threads

Top