Boolean tests [was Re: Attack a sacred Python Cow]
pavlovevidence at gmail.com
Tue Jul 29 22:53:07 CEST 2008
On Jul 29, 4:08 pm, Erik Max Francis <m... at alcyone.com> wrote:
> Carl Banks wrote:
> > On Jul 29, 1:30 pm, Carl Banks <pavlovevide... at gmail.com> wrote:
> >> On Jul 29, 5:15 am, Heiko Wundram <modeln... at modelnine.org> wrote:
> >>> I can't dig up a simple example from code I wrote quickly, but because of the
> >>> fact that explicit comparisons always hamper polymorphism
> >> I'm not going to take your word for it. Do you have code that
> >> demonstrates how "if x" improves polymorphism relative to simple
> >> explicit tests?
> > And, in case it wasn't obvious, the way to demonstrate that "if x"
> > improves polymorphism relative to simple explicit tests would be
> > posting an example where "if x" works but a simple explicit test
> > doesn't. So don't accuse me of changing the question on you: it's the
> > same question.
> It's pretty elementary, and people thought just describing the issue of
> polymorphism and duck-typing was sufficient to explain it. Since it
> apparently isn't:
> Let's say you come up with some kind of custom sequence class. You want
> to act like any native sequence type (list, tuple, array, string, etc.)
> in all reasonable ways (length testing, iteration, indexing, etc.) so
> that it can be used in place of these things in code that doesn't
> require explicit types. You know, standard polymorphism and duck-typing.
> So you want a test for whether your custom sequence isn't empty. To
> create an "simple, explicit test" would be defined an `isntEmpty` method
> that you can call, like so:
> if myObject.isntEmpty():
> # then do something
> However, this wouldn't be polymorphic since now someone would have to
> call a "simple, explicit test" that doesn't exist on all the other
> sequence-like objects. Therefore, you've broken polymorphism.
> The solution is to override the `__nonzero__` method so that you can use
> Boolean testing, just like all the other sequence-like objects:
> if myObject:
> # then do the same thing
> Now people who use your custom sequence type don't have to write special
> code, and code written to deal with sequences using duck typing (which
> is typically nearly all Python code) don't have to know anything special
> about your custom sequence class.
Bzzt. "if len(x)!=0" is a simple explicit that would work for this
class and all built-in containers. (Or should--Steven D'Aprano's
objections notwithstanding, any reasonable container type should
support this invariant. From a language design standpoint, an "empty"
builtin could have been created to simplify this even more, but since
there isn't one len(x)!=0 will have to do.)
Let me reframe the question to see if we can make some headway.
The vast majority of true/false tests fit into one of the following
1. Testing the explicit result of a boolean operation (obviously)
2. Testing whether a numeric type is nonzero.
3. Testing whether a container type is empty.
4. Testing whether you have a (non-numeric, non-container) object of
some sort, or None.
There's a few other cases, but let's start with these to keep things
simple and add other cases as necessary.
We already know that cases 2, 3, and 4 can, individually, be converted
to a simple explicit test (using x!=0, len(x)!=0, and x is not None,
respectively). As long as you know which kind of object you're
expecting, you can convert the implicit to an explicit test.
Now, you guys keep whining "But what if you don't know what kind of
object you're expecting?!!" It's a fair question, and my belief is
that, in practice, this almost never happens. Duck typing happens
between numeric types often, and between container types often, but
almost never between both numeric and container types. Their usages
are simply too different.
So I present another question to you: Give me an useful, non-trivial,
example of some code that where x could be either a numeric or
container type. That would be the first step to finding a
counterexample. (The next step would be to show that it's useful to
use "if x" in such a context.)
Once again, I'm invoking the contraint against simply using x in a
boolean context, or passing x to a function expecting a boolean
doesn't count, since in those cases x can be set to the result of the
explicit test. So none of this:
def nand(a,b): return not (a and b)
Or anything trivial like this:
def add(a,b): return a+b
More information about the Python-list