missing 'xor' Boolean operator

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

Ethan Furman

Jean-Michel Pichavant said:
Steven said:
On Thu, 16 Jul 2009 15:53:45 +0200, Jean-Michel Pichavant wrote:


Given three result codes, where 0 means "no error" and an arbitrary non-
zero integer means some error, it is simple and easy to write:

failed = result_1 or result_2 or result_3

The equivalent:

failed = (result_1 != 0) or (result_2 != 0) or (result_3 != 0)
# or if you prefer:
succeeded = (result_1 == 0) and (result_2 == 0) and (result_3 == 0)

[snip]

This is, I guess, where we disagree. I find the second proposal less
error prone, and universally understandable unlike the first one.

Careful! The very few (if any) things in this world that can be
considered "universally understandable" do *not* include any programming
language! :)
It may
be verbose, it may look even lame to some people, but in the end this is
perfectly reliable, because you manipulate only False or True within the
boolean operations.

The first form does not clearly show what is the failed criteria. It
just happens by coincidence that in this case the failed criteria
matches the Nothingness of result_1, result_2, result_3. What if results
may be 'OK' or 'KO'.

As the programmer, particularly a Python programmer, you should be
taking advantage of Python's strengths, of which this is one. If, as
you say, some function uses a "something" value to indicate an
undesirable result, then you have to use something akin to your last
statement.


~Ethan~
 
S

Steven D'Aprano

Steven said:
On Thu, 16 Jul 2009 15:53:45 +0200, Jean-Michel Pichavant wrote:


Given three result codes, where 0 means "no error" and an arbitrary
non- zero integer means some error, it is simple and easy to write:

failed = result_1 or result_2 or result_3

The equivalent:

failed = (result_1 != 0) or (result_2 != 0) or (result_3 != 0) # or if
you prefer:
succeeded = (result_1 == 0) and (result_2 == 0) and (result_3 == 0)
[snip]

This is, I guess, where we disagree. I find the second proposal less
error prone, and universally understandable unlike the first one. It may
be verbose, it may look even lame to some people, but in the end this is
perfectly reliable, because you manipulate only False or True within the
boolean operations.

Because it is verbose, it is more error-prone. The more code you have to
write, the more opportunities you have to make mistakes.

(This holds up to a point, beyond which being more and more terse also
leads to more errors.)

Boolean algebra is notorious for programmer errors. The more complicated
the boolean expression, the more often programmers get it wrong. The more
book-keeping they have to do, the easier it is to get it wrong. All those
(result != 0) comparisons are mere book-keeping, they don't add anything
to the code except to force the flag to be True or False.


The first form does not clearly show what is the failed criteria.

Of course it does: at least one of the three result codes is non-zero. As
a bonus, failed will be assigned the first non-zero result code (if any).

Your preferred form, on the other hand, folds all the possible error
codes into True, throwing away useful information:
True



It
just happens by coincidence that in this case the failed criteria
matches the Nothingness of result_1, result_2, result_3. What if results
may be 'OK' or 'KO'.

Obviously the test you write depends on the data you have to work with.
Do you think that's surprising?

failed = result_1 or result_2 or result_3 won't work.

Not in the example you gave, no. Although if I had to work with lots and
lots of strings of the form 'OK' and 'KO', I'd consider sub-classing
string:
.... def __nonzero__(self):
.... if self == 'OK': return True
.... elif self == 'KO': return False
.... else:
.... raise ValueError('invalid result code')
........ print "Success!"
.... else: print "Failed!"
....
Failed!


(I wouldn't bother if I only needed one or two such tests, but if I had
lots of them, I'd consider it.)

failed = (result_1 =='KO') or (result_2 =='KO') or (result_3 =='KO') is
lame but reliable.


Yes, it's reliably complicated, reliably easy to get wrong, reliably
harder to read, and it reliably throws away information.

But apart from those disadvantages, it does the job you want it to do.
 
E

Emile van Sebille

On Thu, 16 Jul 2009 15:53:45 +0200, Jean-Michel Pichavant wrote:


Given three result codes, where 0 means "no error" and an arbitrary non-
zero integer means some error, it is simple and easy to write:

failed = result_1 or result_2 or result_3

The equivalent:

failed = (result_1 != 0) or (result_2 != 0) or (result_3 != 0)
# or if you prefer:
succeeded = (result_1 == 0) and (result_2 == 0) and (result_3 == 0)
[snip]

This is, I guess, where we disagree. I find the second proposal less
error prone, and universally understandable unlike the first one. It may
be verbose, it may look even lame to some people, but in the end this is
perfectly reliable, because you manipulate only False or True within the
boolean operations.

The first form does not clearly show what is the failed criteria. It
just happens by coincidence [/QUOTE]

No -- it happens by design because the premise is 'where 0 means "no
error" and an arbitrary non-zero integer means some error'.
that in this case the failed criteria
matches the Nothingness of result_1, result_2, result_3. What if results
may be 'OK' or 'KO'.

Which by definition won't happen for the example cited...
failed = result_1 or result_2 or result_3
won't work.

.... so you certainly wouldn't write a test that couldn't properly
determine success or failure.
failed = (result_1 =='KO') or (result_2 =='KO') or (result_3 =='KO') is
lame but reliable.

In this case I'd write something that meets the specs of the problem
your addressing...

failed = 'KO' in (result_1,result_2,result_3)

Emile
 
D

Dr. Phillip M. Feldman

Suppose that 'xor' returns the value that is true when only one value is
true, and False otherwise. This definition of xor doesn't have the standard
associative property, that is,

(a xor b) xor c

will not necessarily equal

a xor (b xor c)

To see that this is the case, let a= 1, b= 2, and c= 3.

(a xor b) xor c

yields 3, while

a xor (b xor c)

yields 1. So, I'd prefer an xor operator that simply returns True or False.

Phillip
 
M

Mark Dickinson

I was saying that using boolean operators with object instead of boolean
values is error prone,

I agree with this to some extent. After all, Python conditional
expressions were eventually introduced in response to buggy uses of
the 'a and b or c' idiom. See PEP 308, and:

http://mail.python.org/pipermail/python-dev/2005-September/056546.html

In my own code, I'm finding myself increasingly using conditional
expressions where I would once have used 'and' or 'or':

daysInAdvance = int(inputVar) if inputVar is not None else 0
 
E

Ethan Furman

[fixed for bottom-posting]

Dr. Phillip M. Feldman said:
> Suppose that 'xor' returns the value that is true when only one value is
> true, and False otherwise. This definition of xor doesn't have the standard
> associative property, that is,
>
> (a xor b) xor c
>
> will not necessarily equal
>
> a xor (b xor c)
>
> To see that this is the case, let a= 1, b= 2, and c= 3.
>
> (a xor b) xor c
>
> yields 3, while
>
> a xor (b xor c)
>
> yields 1. So, I'd prefer an xor operator that simply returns True or False.
>
> Phillip
>

You are, of course, free to write your version however it makes sense to
you and your team. :)

Since the 'and' and 'or' already return objects (and objects evaluate to
true or false), then 'xor' should behave likewise, IMO. I expect that
would be the case if it were ever added to the language.

~Ethan~
 
M

Mark Dickinson

Dr. Phillip M. Feldman wrote:
 > Suppose that 'xor' returns the value that is true when only one value is
 > true, and False otherwise.  This definition of xor doesn't have the
standard
 > associative property, that is,
 >
 > (a xor b) xor c
 >
 > will not necessarily equal
 >
 > a xor (b xor c)
 >
 > To see that this is the case, let a= 1, b= 2, and c= 3.
 >
 > (a xor b) xor c
 >
 > yields 3, while
 >
 > a xor (b xor c)
 >
 > yields 1.  So, I'd prefer an xor operator that simply returns True or
False.
 >
 > Phillip
 >

You are, of course, free to write your version however it makes sense to
you and your team.  :)

Since the 'and' and 'or' already return objects (and objects evaluate to
true or false), then 'xor' should behave likewise, IMO.  I expect that
would be the case if it were ever added to the language.

I'm not so sure. Did you ever wonder why the any() and all()
functions introduced in 2.5 return a boolean rather than returning
one of their arguments? (I did, and I'm still not sure what the
answer is.)

Mark
 
E

Ethan Furman

Mark said:
I'm not so sure. Did you ever wonder why the any() and all()
functions introduced in 2.5 return a boolean rather than returning
one of their arguments? (I did, and I'm still not sure what the
answer is.)

Mark


Very good question -- I likewise do not know the answer. I will only
observe that any() and all() are functions, while 'and' and 'or' are
not. If one wanted the object-returning behavior one could string
together 'or's or 'and's instead.

~Ethan~
 
A

Albert van der Horst

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 ?

No. I think it is because and/or can be extended to be sensible
in a context where objects can be used. (What others have expressed
as having short-circuit evaluation. So sce indeed is the underlying
reason that and/or can be extended sensibly to objects.)

Remains whether we need an xor that only works and requires that
both operands are booleans. That one we have already!
It is called != .

(a!=b)!=c
and
a!=(b!=c)

are the same for booleans, so can indeed be expressed
a!=b!=c (associativy of xor)
Groetjes Albert
 
T

Terry Reedy

Albert said:
Remains whether we need an xor that only works and requires that
both operands are booleans. That one we have already!
It is called != .

(a!=b)!=c
and
a!=(b!=c)

are the same for booleans, so can indeed be expressed
a!=b!=c (associativy of xor)

Not in Python
True

In Math and Python, a<b<c means a<b and b<c, not (a<b)<c or a<(b<c).
!= is a comparison operator like <, not an arithmetic operator like +
(or logical xor). If one has 0/1 or True/False values, we have
arithmetic xor already, ^, which works as expected.
False

Terry Jan Reedy
 
G

greg

Terry said:
In Math and Python, a<b<c means a<b and b<c, not (a<b)<c or a<(b<c).
!= is a comparison operator like <,

Although Python extends the chaining principle to
!=, this is somewhat questionable, because
a < b and b < c implies a < c, but a != b and
b != c does not imply a != c.

I'm not sure I've ever seen a mathematician
write a != b != c, but if I did, I would tend
to think he meant to say that none of a, b,
c are equal to any other. That's not what it
means in Python, though.
 
T

Terry Reedy

greg said:
Although Python extends the chaining principle to
!=, this is somewhat questionable, because
a < b and b < c implies a < c, but a != b and
b != c does not imply a != c.

I'm not sure I've ever seen a mathematician
write a != b != c, but if I did, I would tend
to think he meant to say that none of a, b,
c are equal to any other. That's not what it
means in Python, though.

However, == is transitive, and a == b == c is quite common.
It would hardly do to have different rules for !=.

Either we have a uniform rule for a compare_op b compare_ob c, as we do,
or we have several fussy rules that would be hard to remember.
 

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
474,201
Messages
2,571,049
Members
47,652
Latest member
Campbellamy

Latest Threads

Top