missing 'xor' Boolean operator

  • Thread starter Dr. Phillip M. Feldman
  • Start date
T

Tim Golden

Steven said:
I've often wished there was too, for the sake of completeness and
aesthetics, I'd love to be able to write:

a xor b

instead of defining a function xor(a, b).

Unfortunately, outside of boolean algebra and simulating electrical
circuits, I can't think of any use-cases for an xor operator. Do you have
any?

I was pondering on this yesterday, and the only case I've
come across in my code -- and it's reasonably common --
is checking that one and only one of two params has been
passed. I have code which wants, say, an id or a name
but doesn't want both. It's hardly difficult to write the
check even now, but an built-in xor would make it fractionally
cleaner.

TJG
 
P

pdpi

I'm well aware of the fact that I've described something differently.
'xor' can be explained as 'check if exactly one element of two elements
is true'. My algorithms describes a super xor, aka 'check if exactly one
element of n elements is true'.

Christian

Well, I just wouldn't call it a "super xor" then, when "unicity test"
works much better -- especially as an alternative to an actual xor
without any specification to the actual intended functionality except
the exception text.
 
H

Hendrik van Rooyen

Steven D'Aprano said:
Unfortunately, outside of boolean algebra and simulating electrical
circuits, I can't think of any use-cases for an xor operator. Do you have
any?

A bitwise xor is a poor man's comparator - if the result is binary zero,
the operands were equal, no matter what they represented.

Not much use in python, though.

- Hendrik
 
M

MRAB

Steven said:
I've often wished there was too, for the sake of completeness and
aesthetics, I'd love to be able to write:

a xor b

instead of defining a function xor(a, b).

Unfortunately, outside of boolean algebra and simulating electrical
circuits, I can't think of any use-cases for an xor operator. Do you have
any?
The problem is that 'and' and 'or' are not limited to Boolean values:

'and' returns the first false value or the last true value.

'or' returns the first true value or the last false value.

What values should 'xor' return? IMHO, if only one of the values is true
then it should return that value, otherwise it should return False.

1 xor 0 => 1
0 xor 2 => 2
1 xor 2 => False
0 xor 0 => False

This is because it's a Boolean operator, so it should fall back to
Boolean values when necessary, like 'not':

not 0 => True
not 1 => False

Also:

x and y and z => (x and y) and z
x or y or z => (x or y) or z

therefore:

x xor y xor z => (x xor y) xor z
 
R

Robert Kern

While everyone's trying to tell the OP how to workaround the missing xor
operator, nobody answered the question "why is there no xor operator ?".

If the question was "Why is there no 'or' operator ?", would "because A
or B <=> not(not A and not B)" be a proper answer ?

That's not the only answer the OP has been given. The most compelling answer is
that an "xor" keyword cannot be implemented with similar semantics to "and" and
"or", in particular short-circuiting and returning one of the actual inputs
instead of a coerced bool.

--
Robert Kern

"I have come to believe that the whole world is an enigma, a harmless enigma
that is made terrible by our own mad attempt to interpret it as though it had
an underlying truth."
-- Umberto Eco
 
H

Hrvoje Niksic

Jean-Michel Pichavant said:
While everyone's trying to tell the OP how to workaround the missing
xor operator, nobody answered the question "why is there no [boolean]
xor operator ?".

Probably because there isn't one in C. The bitwise XOR operator, on the
other hand, exists in both C and Python.
If the question was "Why is there no 'or' operator ?", would "because
A or B <=> not(not A and not B)" be a proper answer ?

Note that in Python A or B is in fact not equivalent to not(not A and
not B).
 
P

Paul Rubin

Hrvoje Niksic said:
While everyone's trying to tell the OP how to workaround the missing
xor operator, nobody answered the question "why is there no [boolean]
xor operator ?".

Probably because there isn't one in C. The bitwise XOR operator, on the
other hand, exists in both C and Python.

A non-bitwise XOR really sounds almost useless.
 
J

Jean-Michel Pichavant

Hrvoje Niksic wrote:
[snip]
Note that in Python A or B is in fact not equivalent to not(not A and
not B).
>>> l = [(True, True), (True, False), (False, True), (False, False)]
>>> for p in l:
.... p[0] or p[1]
....
True
True
True
False.... not(not p[0] and not p[1])
....
True
True
True
False
Did I make twice the same obvious error ?

JM
 
E

Emile van Sebille

On 7/15/2009 10:43 AM Jean-Michel Pichavant said...
Hrvoje Niksic wrote:
[snip]
Note that in Python A or B is in fact not equivalent to not(not A and
not B).
l = [(True, True), (True, False), (False, True), (False, False)]
for p in l:
... p[0] or p[1]
...
True
True
True
False... not(not p[0] and not p[1])
...
True
True
True
FalseDid I make twice the same obvious error ?

No -- but in the not(not... example it doesn't short-circuit.

Emile
 
M

Miles Kaufmann

Hrvoje Niksic wrote:
[snip]
Note that in Python A or B is in fact not equivalent to not(not A and
not B).
l = [(True, True), (True, False), (False, True), (False, False)]
for p in l:
... p[0] or p[1]
[snip]
Did I make twice the same obvious error ?


Try again with:

l = [('foo','bar'), ('foo', ''), ('', 'bar'), ('', '')]

-Miles
 
M

Miles Kaufmann

On 7/15/2009 10:43 AM Jean-Michel Pichavant said...
Hrvoje Niksic wrote:
[snip]
Note that in Python A or B is in fact not equivalent to not(not A
and
not B).
Did I make twice the same obvious error ?

No -- but in the not(not... example it doesn't short-circuit.

No; like 'A or B', 'not (not A and not B)' does in fact short-circuit
if A is True. (The 'and' condition does not have to evaluate the
right operand when 'not A' is False.)

-Miles
 
T

Terry Reedy

Tim said:
I was pondering on this yesterday, and the only case I've
come across in my code -- and it's reasonably common --
is checking that one and only one of two params has been
passed. I have code which wants, say, an id or a name
but doesn't want both. It's hardly difficult to write the
check even now, but an built-in xor would make it fractionally
cleaner.

I think I would just have one parameter id_name or identifier so no
check is needed. This is a common idiom in Python where names are not
typed. Example: param 'source' is a string (with a file name to be
opened) or an already opened file. If you want two local vars inside the
function, that should be kept private to the function.

tjr
 
D

Dr. Phillip M. Feldman

I did initially ask for an infix xor operator, but eventually gave up on
this. I like the first of your two one-line solutions below; this is clean
and easy to understand. Thanks! I'd still like to be able to write an
expression like '(a and b) xor (c and d) xor (e and f)', but it looks as
though that can't be done.



<snip>

Well, that's not exactly what you originally asked for. But it's
still a one-liner:

def xor(*args): return bool(sum(map(bool, args)) % 2)

or perhaps

def xor(*args): return bool(len(filter(None, args)) & 1)
 
R

Robert Kern

You're right about that!. It's used everywhere in:

- coding and encryption theory (and practice) (e.g.,
http://www.mathcs.emory.edu/~whalen/Hash/Hash_Articles/IEEE/XOR-based hash functions.pdf)
- emulation and simulation of hardware (since all but the most trivial
logic circuits are likely to include XOR-gates)
- hence, for design of new architectures or simulators or virtual
machines and simplification of existing ones--(e.g.,
http://www.date-conference.com/archive/conference/proceedings/PAPERS/1999/DATE99/PDFFILES/05A_6.PDF)
and
http://bochs.sourceforge.net/Virtualization_Without_Hardware_Final.pdf
which includes:

"The answer relies on the observation that subtracting an integer
value from 0xFFFFFFFF gives the same result as XOR-ing that same value
to 0xFFFFFFFF."

And, perhaps the most useful use of all, for Bouton's solution of the
game of Nim--both for the proof that his strategy "solves" the game
and for an easy implementation of a Nim-playing program--and the only
operator needed is XOR (e.g., http://www.wordiq.com/definition/Nim).

All of those can use the bitwise XOR operator, not the boolean XOR. Python
already has the ^ operator for those purposes.

--
Robert Kern

"I have come to believe that the whole world is an enigma, a harmless enigma
that is made terrible by our own mad attempt to interpret it as though it had
an underlying truth."
-- Umberto Eco
 
M

Mark Dickinson

I'd also guess that 'xor' would be much less used than 'and' or 'or',
but maybe that's just a reflection of the sort of code that I tend to
write.

You're right about that!. It's used everywhere in:
[snip examples and references]

Those examples are (almost) all about the *bitwise* xor operator,
which exists in Python ('^') and, as you point out, has no shortage of
good uses. The discussion was about a *logical* xor, to parallel the
existing 'and' and 'or' operators.
 
A

Anthony Tolle

Current Boolean operators are 'and', 'or', and 'not'.  It would be nice to
have an 'xor' operator as well.

My $0.02 on this discussion: There would be nothing gained by having
non-bitwise XOR operator. You can't short-circuit XOR, because you
must evaluate all operands to produce a result. Consequently,
returning the "true" item also doesn't make much sense. XOR is closer
to the the logical NOT operator than it is to AND or OR.

Here's my own take on a function that can handle any number of
arguments (it should probably raise an exception for 0 or 1 arguments,
but I'm lazy):

def xor(*operands):
if operands:
operands = list(operands)
a = bool(operands.pop(0))
while operands:
b = bool(operands.pop(0))
if a:
if b:
a = False
elif b:
a = True
return a
return False
 
J

Jean-Michel Pichavant

Miles said:
Hrvoje Niksic wrote:
[snip]
Note that in Python A or B is in fact not equivalent to not(not A and
not B).

l = [(True, True), (True, False), (False, True), (False, False)]
for p in l:
... p[0] or p[1]
[snip]
Did I make twice the same obvious error ?


Try again with:

l = [('foo','bar'), ('foo', ''), ('', 'bar'), ('', '')]

-Miles
Didn't know that.
So if I resume:
- not 'foo' => False
- 'foo' or 'foo' => 'foo'

I may be missing something, but honestly, Guido must have smoked some
heavy stuff to write such logic, has he ?

Let's play again
False or 'foo' => 'foo'
False and 'foo' => False

So funny. I would have expected boolean operators to return a boolean
value. I should have read the f*** manual (this is an anticipated RTFM
counter-attack). Anyway Miles, thanks for the update.

JM
 
N

Nobody

So if I resume:
- not 'foo' => False
- 'foo' or 'foo' => 'foo'

I may be missing something, but honestly, Guido must have smoked some
heavy stuff to write such logic, has he ?

Several languages (e.g. Lisp, Bourne shell) behave the same way, i.e. "or"
returns the first element which is considered true while "and" returns the
last element provided that all preceding elements are considered true.
Let's play again
False or 'foo' => 'foo'
False and 'foo' => False

So funny. I would have expected boolean operators to return a boolean
value.

In Python, almost everything is a boolean value.

Compare with Lisp, where everything is a boolean value: nil (the empty
list) is false and everything else (including integer zero) is true.
 
C

Chris Rebert

I've often wished there was too, for the sake of completeness and
aesthetics, I'd love to be able to write:

a xor b

instead of defining a function xor(a, b).

Unfortunately, outside of boolean algebra and simulating electrical
circuits, I can't think of any use-cases for an xor operator. Do you have
any?

Since xor in set theory is the symmetric difference,  perhaps we'd
like to know all items in exactly one of two word lists or
dictionaries, or anything else we could easily set-ize:
cheese = set(['cheddar', 'limburger', 'stilton'])
stinky = set(['skunk', 'limburger', 'stilton', 'polecat', 'doggy-doo', 'civet'])
nasty = set(['doggy-doo', 'polecat', 'limburger', 'Perl'])
cheese & stinky # stinky cheese set(['limburger', 'stilton'])
cheese ^ stinky # either cheese or stinky but not both set(['doggy-doo', 'civet', 'polecat', 'skunk', 'cheddar'])
cheese ^ stinky ^ nasty # in an odd number of these sets (1 or 3)
set(['civet', 'cheddar', 'Perl', 'limburger', 'skunk'])

Who hasn't needed that occasionally?

This discussion is about adding a *logical* operator for use in
boolean expressions. We obviously already have ^ for non-boolean use.

Cheers,
Chris
 

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,774
Messages
2,569,598
Members
45,152
Latest member
LorettaGur
Top