C++ etc (was Re: ACCEPTED: PEP 285)

Alex Martelli aleax at aleax.it
Thu Apr 4 04:13:58 EST 2002


djw wrote:

> Pardon my ignorance (I've only been working with Python for a short
> while), but I don't understand why an idiom like:
> 
> if x == True:
> 
> would be/should be an error (or warning initially)

Ignorance is no crime!  Let's see if we can help you, and not just
in a Python context either.


> I see C/C++ code
> like this all the time:

So did I use to, as long as a very substantial part of my job was
teaching / tutoring / mentoring in C++ (i.e., up to 2 months ago).

Which IS a good part of why I quit that job (otherwise quite good
and fulfilling) and switched to one where I'm basically dealing
with Python full-time.  I'm still a Brainbench MVP for C++, and if
some C++ code needs dealing with I'm not going to pull back, but I
dearly hope it WON'T be "like this" (Boost Python's excellent use
of C++ and other really masterful C++ is more what I have in mind).

OK, back into "teach / tutor / mentor in C++" mindset, then...:

> bool x;
> x = Foo(Bar);

This is very, *VERY* bad C++ style.  Get into the habit of initializing
EVERY variable contextually with its declaration.  This is really the
ONLY way to ensure you won't be faced with uninitialized variables.

When you're a real master at C++, then and only then can you declare
without initializing in those extremely rare cases where this is
truly what you want to do.  But wait for a year or three of intense
C++ practice before you self-certify yourself as ready for that.  (Or
take the C++ test with Brainbench, or other similar self-assessment
procedure, and convince yourself that you're in the top percentile of
all C++ users).


> if (x==true)

This is almost as bad, for a different reason.  C++ forces you to
code a lot of boilerplate already.  Do *NOT* code boilerplate that
is NOT necessary: EVERY "dot of ink" on the "page" should be either
meaningful or mandated by the language.  (If you follow a style guide
that forces you to put meaningless dots of ink on the page beyond
those that the language itself mandates, change the guide).

Boilerplate hides bugs and can even cause them.  Some day,
somewhere, somebody will accidentally skip one of those two
'=' characters and will be working with a compiler that does
not scream to high heavens when you do (e.g. MS VC++ 6).  Then
instead of a comparison you will be testing an assignment,
ignoring the previous (actual!) value of 'x', and take the
'true' branch in what is actually an unconditional manner.

You should take every precaution to ward against such problems.
If your current compiler is able to warn you against them, turn
those warnings on, but don't rely EXCLUSIVELY on them, because
one day you WILL be using another compiler (or your code will
be maintained by somebody else who does some edits and then
uses a different compiler, etc, etc).  I would even suggest (I
have had scarce luck convincing people of this!-) to code
comparisons habitually with the constant on the LEFT, when
the comparison is in fact necessary, as in "if(23==z)" -- THIS
habit would basically make the skip-an-equals bug non-existent
.
But even if you can't or won't do that (not all people realize
that == defines an equivalence relationship, so you CAN count
on it being commutative, as well as reflexive and transitive!-),
there are other good habits you SHOULD definitely pick up, and
will help avoid the bug.  One of them is, NEVER compare any
boolean with the constants true and false.  Never.  If you never
do that, the bug will never bite in this specific context.


But, there is more.  You should always maximize polymorphism
in your code even when you're not exploiting it actively.  One
day you WILL want to make this code into a template.  The
fewer gratuitous non-polymorphic constructs your code embodies,
the less exertion will it take to templatize it, and the fewer
bugs will be left in it when you're done.  I.e., one day you
will want to have this code inside a

template <class T>
   ...
T x = Foo(Bar);


Now, if the next statement is "if(x)", your template will be
perfectly working with many diverse T, such as int, X*, and
so on.  If it's "if(x==true)" instead, you may forget to
edit it, the compiler will not complain if T is int, and
the behavior will NOT be equivalent.  Don't do it.


Besides, where do you stop?  x and x==true (when x is bool)
are absolutely equivalent -- and so are x==true==true and
(x==true)==true and x==(true==true) and ... so where do you
stop?  The only sensible answer: stop at once and just
write x.  The fewer extraneous, redundant and useless
'==' and 'true' tokens you have, the better.



> Of course, this could also be written in the more abbreviated form as
> well. But, why force that on the programmer? I really prefer the more
> explicit  comparison of x with true rather than the if(x) idiom. Myself,

It's a misguided preference, and it WILL cause you problems down
the road.

> being a newbie Python programmer (but not a newbie programmer in C, C++,
> etc), I would find it somewhat confusing that I could not compare a
> variable to a valid value for the variable using what appears to be a
> valid operator.

Making this comparison an ERROR would be a bit overboard, perhaps.

The language cannot forbid every absurd usage (C++ even happily
allows "if(x=true)", although finding a sensible use case for this
is impossible for me -- forbidding it would require complicating
the already-complicated language rules yet further, and there's a
limit to the amount of complication even C++ can tolerate!-).  A
warning, based on the heuristic consideration that this usage is
VERY error-prone and has absolutely NO good reason to recommend
it, is just about right, IMHO.


> Am I missing something more subtle here?

I think you are, as I tried to indicate -- even in a C++ context.


In Python, it's even more blatant, for several reasons.  First
of all, you're "always writing templates" in a sense: when a very
experienced C++ coder meets Python, he or she often gets this
eerie sense that, yes, it FEELS sort of like coding templates,
and for good reason -- Python is intrinsically "generic" just
like C++ is only within templates (the syntax is utterly different,
checks are runtime rather than compile-time, etc, but it's still
quite close).  Second, Python strives to MINIMIZE boilerplate, so
any boilerplate you gratuitously add stands out like a sort thumb.
Etc, etc.  But you should really consider adopting a consistent
habit of eschewing comparisons with boolean constants in just
about every language you may ever use...


Alex




More information about the Python-list mailing list