Unsurprisingly, there have been quite a few reactions to my small Python rant
earlier. It’s good to see people stand up for their language, that’s what
makes our profession so unique.
Here are a few comments and my reactions to them:
Complete object orientation was built in from the start
That’s not true, see below for more on Python’s history.
It’s true that it allows you to mix object-oriented and script-style code
but I really don’t see what’s wrong with that, since you get the best of
both worlds.
Not always. I think languages such as Ruby and Groovy definitely enable
both types of programming and offer the best of both worlds, but Python has made
a lot of compromises when adopting various styles of programming, and my
experience with Python has been less about choosing between two great
alternatives than picking the least of two evils.
By the way your code has 4 "it" and I’ll let you count the different
semantics to yourself.
I already did: there are two. One to declare the parameter and
the other one to use it inside the closure. And that’s how it should be.
I think it’s just a matter of what you’re used to. For me as a Python and
Java programmer, the Ruby code you show looks just as unnatural and weird as the
Python code looks to you. But maybe that’s just because I’m not used to
seeing Ruby, just as you’re not used to seeing Python code.
Fair enough. For the record, I read a couple of Python books and I do
see a decent amount of Python code every day, so I’m certainly used to reading
it (not as much writing it, though). But my dislike for
Python is caused by more than the odd for syntax I commented on in my previous
entry, but let me elaborate on that.
C offers a for loop similar to Python’s (a bit less powerful actually) which
is so flexible that pretty much any language that appeared after C provided a
similar construct. Having said that, I still think that C is more elegant than
Python because it’s more consistent.
The problem with Python is that it came out at a time that turned out to be
pivotal in software history. The software world was slowly realizing the
power of several programming paradigms (imperative, functional, declarative,
etc…) and set out to explore them all through different languages (C++,
Modula, Eiffel, Haskell, Prolog, etc…). Python started as a very basic
script language that mimicked the already bare-bone syntax of C while doing away
with most of its type safety (a layer was pretty thin to start with).
Even
though object-oriented concepts were slowly emerging as a must-have for
industrial software programming, the idea of
including them in Python made as much sense as it would to add templates to
Ruby, so creating Python without any of these advanced features made
perfect sense (Python didn’t even have support for static initially!).
But things changed and some of these advanced features turned out to be not
only necessary but essential for any language that pretended to be of industrial
caliber. So Python tried to adapt and started to incorporate a mishmash of
features from various origins.
Unfortunately, Python wasn’t designed to grow. It didn’t follow the
recipes laid out by Guy Steele’s seminal paper
Growing a language, and as such,
the inclusion of all these features took a heavy toll on Python’s syntax
(sometimes acceptable) and Python’s consistency (much worse).
For example,
static was retrofitted in Python and must now be achieved like this:
def say_hello(cls): print X.message say_hello = classmethod(say_hello)
That’s right: not only do you make a method static by invoking a
magic function on it, you actually need to reassign the method to the value
returned by this magic method.
I’m sure there are very good technical reasons
for this kind of wart, but that’s exactly the problem I have with Python:
these reasons were obviously motivated by the complexity that Guido van Rossum
had to face in order to incorporate these new features, and not really aimed at
making the language simpler for Python users. I can’t imagine there would
be any other reason (readability?) than Guido having a problem adding a keyword
to his language, or coming up with another less awkward syntax (Ruby does it in
a creative way, but I still prefer the static keyword approach).
And this was just to add static. Retrofitting
more complex object-oriented language features to Python has been even more problematic, and
the ubiquitous and useless self keyword is just the tip of the iceberg
(take a look at how Python implements private/protected or how
accessors work).
The same can be said about Python’s mixed support for features coming from the
functional world. Generators, lambdas, closures, continuations, etc…
are all implemented with strange restrictions that make guessing the right
behavior or syntax almost impossible (to such an extent that some of these
features are actually being considered for removal, which is probably the worst
thing you can do to a language).
If you are interested in more details about my feelings about Python, here
are a few
older
entries
I
wrote on
this topic.
Anyway.
At the end of the day, elegance is something that just cannot
be argued because everyone has different criteria to define it. Throughout
the years and after studying quite a few languages, I have reached a point where
languages need to possess a certain set of features in terms of syntax and
semantics to get my attention. Over and over again, I have tried hard to
like Python because, frankly speaking, its momentum is undeniable. But it
just never clicked, while my attraction for languages such as Lisp, Java, Ruby
and more recently, Groovy, happened within a matter of hours of tinkering.
Wherever your preferences lie, keep your mind open and learn at
least a new language every year. It will make you a better developer.