Why isn't there a logical XOR operator?

  • Thread starter Christopher Benson-Manica
  • Start date
S

Sidney Cadot

Tom said:
== is a short circuit though. The intention would be that ^^ would be a
short-circuit (otherwise I don't see the point) and as the others pointed
out you have to evaluate both sides to determine the result (therefore it
cannot short circuit).

What you could do is make ^& and ^| for NAND and NOR (former shorts if left
is zero, latter if left is one) and you'd have all four short-circuits ;-)

Well actually make ^& into ^^ since it's ambiguous with ^&varname, etc...so
you get

^^ = NAND
^| = NOR
|| = OR
&& = AND

I'd prefer a !&& and a !|| operator.

These would go handsomly alongside ||| and &&& operators, but that's
another story.


Regards,

sidney
 
S

Sidney Cadot

pete said:
(!(a) != !(b)) is adequate for the situation.

Well, by the same reasoning we could do away with !=, being as it is that

!((a)==(b)) is adequate for the situation.

The whole point of this discussion is that C obviously lacks a logical
XOR operator, and whether there's a good reason for it. Adequacy doesn't
enter into it, otherwise !, &&, <, and > would suffice.

For my part, I'd be happy to see a ^^ but only if we get logical
"implies" and "equiv" operators as well.

Best regards,

Sidney
 
K

Keith Thompson

Sidney Cadot said:
Tom St Denis wrote: [...]
What you could do is make ^& and ^| for NAND and NOR (former shorts if left
is zero, latter if left is one) and you'd have all four short-circuits ;-)

Well actually make ^& into ^^ since it's ambiguous with ^&varname, etc...so
you get

^^ = NAND
^| = NOR
|| = OR
&& = AND

I'd prefer a !&& and a !|| operator.

These would go handsomly alongside ||| and &&& operators, but that's
another story.

Right, because C doesn't look enough like modem line noise as it is.
:cool:}
 
P

Peter Nilsson

Ben Pfaff said:
For what it's worth, I've added a page to my own personal FAQ
list:
http://www.msu.edu/~pfaffben/writings/clc/logical-xor.html
Anyone have anything to add or dispute?

Short-circuit evaluation is not a _requirement_ of logical operators.
Many other ('old') languages have logical-and and logical-or operators
which are not short-circuited.

I think a more tangable example for the second case would be better.
Otherwise you seem to be dismissing out of hand the 'kludgy' look of
the != alternative. Perhaps...

((a < 0) != (b < 0)) /* one and only one operator is negative
*/

Thirdly, whilst practical use of logical xor is rare, it's rare
because it's relatively complex (in terms of NOT, AND and OR
operations which _easily_ cover 14 of the 16 binary boolean
operations). But when it is needed, it's absense is felt. It wouldn't
be particularly difficult for implementors to cater for.

Lastly, I think the principle reason is quite simply because Dennis
Ritchie didn't think it was necessary at the time (and possibly not
even now.) But AFAIK, there was no serious issue preventing it from
being put into C90 nor C99.

Keith Thompson's point about the macro xor is a good one, but I think
it simply highlights an error in naming (in C++?)
 
C

CBFalconer

Martin said:
.... snip ...


Is "logical exclusive OR" really that hard to understand? The
operator would yield 1 if one and only one of its operands is 0,
and it would yield 0 otherwise.

As others have pointed out, all other logical operators
short-circuit. xor cannot, since the second expression absolutely
must be evaluated. Changing this would cause much greater
confusion than "(!(a) != !(b))" and cohorts.
 
C

Christian Bau

"Tom St Denis said:
how is

if (a ^^ b) { ... }

any diff from

if (a ^ b) { .... }

I would assume that a ^^ b would only check whether a is zero or
nonzero, and whether b is zero or nonzero, and I would assume that a and
b would be allowed to be floating point numbers or pointers.

I might assume that a is evaluated completely before b, with a sequence
point in between, so that ^^ would behave as close as possible like &&
or ||.
 
A

Arthur J. O'Dwyer

As others have pointed out, all other logical operators
short-circuit. xor cannot, since the second expression absolutely
must be evaluated. Changing this would cause much greater
confusion than "(!(a) != !(b))" and cohorts.

*Nobody* is suggesting changing the short-circuiting semantics
of && or ||. But several people *are* suggesting the addition of
a third logical operator, ^^, which performs a logical XOR on its
two operands (after converting them to "boolean" 0 or 1).
The logical XOR, naturally, cannot short-circuit; there's nowhere
for it to short-circuit "to," if you get my drift. However, that
fact has nothing to do with the short-circuiting or not of && and ||.


& : Computes the bitwise AND of its operands.
| : Computes the bitwise OR of its operands.
^ : Computes the bitwise XOR of its operands.

&& : Computes the logical AND of its operands in an efficient
left-to-right manner.
|| : Computes the logical OR of its operands in an efficient
left-to-right manner.
^^ (proposed): Computes the logical XOR of its operands in an
efficient left-to-right manner.

So AIUI, the logical XOR operator would introduce a sequence
point between the evaluation of its operands (which incidentally
none of the suggested remedies do), and it would compute the
answer in a manner "as short-circuited as possible" -- i.e.,
not short-circuited at all.
As the fact that ^^ cannot short-circuit is apparent to anyone
with the ability to think, I don't think its not short-circuiting
is likely to confuse anyone with the ability to program. :)

[Again: I'm a supporter of the status quo out of pessimism,
but I will attempt to demolish arguments that support the status
quo by reasoning alone -- because I think the omission of ^^
*was* a bad idea. Why hack up solutions involving != when what
the algorithm demands is a logical XOR? (...Because that's the
only way the language supports, is why. No deeper reason.) ]

-Arthur
 
S

Sidney Cadot

CBFalconer said:
... snip ...



As others have pointed out, all other logical operators
short-circuit.

Or, as it was once so aptly put: things that are to float must not be
made of stuff that's heavier than water, because the only things we see
now that float are made of stuff that is less heavy than water.
xor cannot, since the second expression absolutely
must be evaluated.

IMO, the short-circuiting property of && and || is incidental; their
being logical operators instead of binary operators is essential.

<rant>
Due to unfortunate historical accident, the concept of logical/boolean
values has ended up in C as a derived property of expressions, where it
should have been a proper type in itself. This is an untidy aspect of
the type system; any properly designed language (which, for all its
merits, C is /not/) has a separate Boolean type, and, therefore,
separate operators and/or operator semantics for Boolean values
(although, perhaps, overloaded on operators that are also meaningful on
other types).

In my opinion, the C approach to logical/boolean values is fundamentally
broken. I would applaud any attempt to plug this particular hole by
widening the difference between bitwise operations on integers, and
logical operations on Booleans (such as introduction of a true logical
XOR), although the flaw is essentially at a deeper level than
introduction of a new operator could ever hope to fix.
</rant>

So, the decision on whether to do short-circuit evaluation or not (if at
all possible) is a question to consider /after/ you decide to properly
distinguish integer/boolean types (or bitwise/logical operators), as in
C). These are separate issues, with the former taking precedence over
the latter. At least, that's how I feel about it.
Changing this would cause much greater
confusion than "(!(a) != !(b))" and cohorts.

Surely, you jest.

If I ever were to encounter "(!(a) != !(b))" in production code, well,
suffice it to say I would not be pleased.


Best regards,

Sidney
 
K

Keith Thompson

Christian Bau said:
I would assume that a ^^ b would only check whether a is zero or
nonzero, and whether b is zero or nonzero, and I would assume that a and
b would be allowed to be floating point numbers or pointers.
Agreed.

I might assume that a is evaluated completely before b, with a sequence
point in between, so that ^^ would behave as close as possible like &&
or ||.

The "&&" and "||" operators have a sequence point *because* they
short-circuit. Since "^^" doesn't (and can't) short-circuit, adding a
sequence point would be more confusing than not doing so.

If I were designing the C language from scratch, I'd probably add a
"^^" operator just for symmetry. But it's too late now. Even if we
could convince the committee to add "^^" to the C200Y standard, we'd
probably be stuck for the next 10 to 20 years with old compilers that
don't implement it. Any code that uses the new operator either
wouldn't be portable to the older compilers, or would have to use #if
tricks to use a C99-compatible XOR on compilers that don't support
"^^" -- which would be far uglier than any of the workarounds we've
already seen here.

Inertia, like gravity, sucks.

<OT>
Perl, whose expression syntax is heavily influenced by C, has "^" as a
bitwise xor operator and "xor" as a logical xor operator.
</OT>
 
C

Christian Bau

Keith Thompson said:
The "&&" and "||" operators have a sequence point *because* they
short-circuit. Since "^^" doesn't (and can't) short-circuit, adding a
sequence point would be more confusing than not doing so.

Here is the reasoning for the sequence point: && doesn't short circuit
if the left part is true, and || doesn't short circuit if the left part
is false. ^^ should behave as much as possible like an && or || that
doesn't short circuit because of the particular value of the left part.

The sequence point in && and || also makes code like this defined:

if (++i == 2 || i == 3) ...
if (++i >= 10 && i <= 20) ...

Without the sequence point there would be undefined behavior.
 
C

Chris Torek

<rant>
Due to unfortunate historical accident, the concept of logical/boolean
values has ended up in C as a derived property of expressions, where it
should have been a proper type in itself.

This may indeed be the case -- as Dennis Himself :) has noted
before, the reason the & and | operators have the "wrong precedence"
(really, their odd position in the ANSI C grammar) is due to a very
early version of the language having no separate "&&" and "||"
operators. Instead, when handling an "if" expression (and perhaps
all "boolean context" expressions such as for and while loops as
well), the compiler treated binary "&" as a logical AND operator.
In other expression contexts, the compiler treated "&" as a bitwise
AND operator.

The operators were split well before 1978 to clean up the situation,
but the grammar was never adjusted to put & and | at "more appropriate"
levels.

(This may well be what you meant; I just thought I would expand
upon the "historical accident" a bit.)

[much snippage]
If I ever were to encounter "(!(a) != !(b))" in production code, well,
suffice it to say I would not be pleased.

If I wanted logical XOR, I would probably do this:

/* LXOR: logical xor. Like && and ||, guarantees left to right
evaluation. Both operands are always evaluated, of course.
The result is the "boolean normalization" of a xor'ed with
the "boolean normalization" of b. */
#define LXOR(a, b) ((a) ? !(b) : !!(b))

and then just use LXOR(expr1, expr2) as needed.

(If I did not care about the order guarantee I might "weaken" the
macro to (!(a) ^ !(b)), and adjust the comment.)
 
C

CBFalconer

Sidney said:
CBFalconer wrote:
.... snip ...


Surely, you jest.

If I ever were to encounter "(!(a) != !(b))" in production code,
well, suffice it to say I would not be pleased.

Alright, how about:

#include <iso646.h>
#define logicalvalue(x) (not(x))
....
if (logicalvalue(a) != logicalvalue(b)) ....
or
if (logicalvalue(a) xor logicalvalue(b)) ....

:)

However I do not jest that the built in expectation of short
circuit performance of && and || should not be confused by yet
another exception for ^^. Bad idea.
 
R

Richard Bos

A *logical* expression a ^^ b ^^ c ^^ d ^^ e
is beyond the understanding of the average human being.

Not really. It means "an odd number of these expressions are true". Of
course, the usefulness of that test is debatable, but it's quite
understandable.

Richard
 
S

stelios xanthakis

Martin Dickopp said:
I guess it would have left-to-right associativity just like &&
and ||, i.e. behave like (a ^^ b) ^^ c. But even if it behaved
like a ^^ (b ^^ c), the result would be the same. Where do you
see a problem?

Martin

The problem is just that this is logically confusing
by itself.

a ^^ b ^^ c

means "not c if a and b are different, and c if a and b are the same".
This is clearly a mess so my point was that although a single ^^
might be useful some times, sequential ^^s are so rare that we
can consider them impossible. Unlike || and && where multiple
such are very frequently used.

A *logical* expression a ^^ b ^^ c ^^ d ^^ e
is beyond the understanding of the average human being.

But no real problem though...

Stelios
 
D

Dik T. Winter

> A *logical* expression a ^^ b ^^ c ^^ d ^^ e
> is beyond the understanding of the average human being.

It is actually quite simple. It is 1 if there are an odd number of
a to e non-zero, 0 otherwise.
 
A

Arjan Kenter

Dik said:
It is actually quite simple. It is 1 if there are an odd number of
a to e non-zero, 0 otherwise.

Which, by the way, could be very different from what someone might want to
express: 'I want an /exclusive/ OR over 5 logical expressions'. That would
sound to me like an expression that yields 1 if exactly one of the 5 logical
expressions is non-zero and 0 otherwise :) The only simple way I see to
express that in C is: !!(a) + !!(b) + !!(c) + !!(d) + !!(e) == 1.

In other words: while 2-operand logical AND and OR are straightforward to
extend to n-operand, and easy to express using C's && and || operators, an
n-operand (logical) XOR may not be so well defined in everyone's mind and
depending on the chosen definition might not be easy to express with ^ (or
with the imaginary/proposed ^^ operator).

So, although Stelios' expression is well within the understanding of human
beings (I will count myself as average at any rate), it is certainly for me
counterintuitive.

Oh boy, is this getting off topic?

--
ir. H.J.H.N. Kenter ^^
Electronic Design & Tools oo ) Philips Research Labs
Building WAY 3.23 =x= \ (e-mail address removed)
Prof. Holstlaan 4 (WAY31) | \ tel. +31 40 27 45334
5656 AA Eindhoven /|__ \ tfx. +31 40 27 44626
The Netherlands (____)_/ http://www.kenter.demon.nl/

Famous last words: Segmentation Fault (core dumped)
 
D

Dik T. Winter

>
> Which, by the way, could be very different from what someone might want to
> express: 'I want an /exclusive/ OR over 5 logical expressions'.

In that case he wants a quinary operator not a chain of binary operators
(he should look at lisp...).

Note that the above chain can be written as such by virtue of the
associativity of the operator. If the operator is not associative
(as multiplication on octonions), it *should* be written with
parenthesis. (And in mathematics that is the definition.)
> Oh boy, is this getting off topic?

In a sense.
 
L

Larry Doolittle

stelios said:
A *logical* expression a ^^ b ^^ c ^^ d ^^ e
is beyond the understanding of the average human being.

Maybe "average human beings" shouldn't try to write or
maintain non-trivial C programs.

That expression is true if an odd number of a, b, c, d,
and e are true.

- Larry
 
C

Christian Bau

A *logical* expression a ^^ b ^^ c ^^ d ^^ e
is beyond the understanding of the average human being.

It means "one, three or five of these are true".
 

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

No members online now.

Forum statistics

Threads
473,770
Messages
2,569,584
Members
45,077
Latest member
SangMoor21

Latest Threads

Top