Friday, October 8, 2010

Alex Martelli on python vs ruby

From comp.lang.python

Erik Max Francis wrote:
> "Brandon J. Van Every" wrote:

>> What's better about Ruby than Python? I'm sure there's something.
>> What is it?

> Wouldn't it make much more sense to ask Ruby people this, rather than
> Python people?

Might, or might not, depending on one's purposes -- for example, if
one's purposes include a "sociological study" of the Python community,
then putting questions to that community is likely to prove more
revealing of informaiton about it, than putting them elsewhere:-).

Personally, I gladly took the opportunity to follow Dave Thomas'
one-day Ruby tutorial at last OSCON. Below a thin veneer of syntax
differences, I find Ruby and Python amazingly similar -- if I was
computing the minimum spanning tree among just about any set of
languages, I'm pretty sure Python and Ruby would be the first two
leaves to coalesce into an intermediate node:-).

Sure, I do get weary, in Ruby, of typing the silly "end" at the end
of each block (rather than just unindenting) -- but then I do get
to avoid typing the equally-silly ':' which Python requires at the
_start_ of each block, so that's almost a wash:-). Other syntax
differences such as '@foo' versus 'self.foo', or the higher significance
of case in Ruby vs Python, are really just about as irrelevant to me.

Others no doubt base their choice of programming languages on just
such issues, and they generate the hottest debates -- but to me that's
just an example of one of Parkinson's Laws in action (the amount on
debate on an issue is inversely proportional to the issue's actual
importance).

One syntax difference that I do find important, and in Python's
favour -- but other people will no doubt think just the reverse --
is "how do you call a function which takes no parameters". In
Python (like in C), to call a function you always apply the
"call operator" -- trailing parentheses just after the object
you're calling (inside those trailing parentheses go the args
you're passing in the call -- if you're passing no args, then
the parentheses are empty). This leaves the mere mention of
any object, with no operator involved, as meaning just a
reference to the object -- in any context, without special
cases, exceptions, ad-hoc rules, and the like. In Ruby (like
in Pascal), to call a function WITH arguments you pass the
args (normally in parentheses, though that is not invariably
the case) -- BUT if the function takes no args then simply
mentioning the function implicitly calls it. This may meet
the expectations of many people (at least, no doubt, those
whose only previous experience of programming was with Pascal,
or other languages with similar "implcit calling", such as
Visual Basic) -- but to me, it means the mere mention of an
object may EITHER mean a reference to the object, OR a call
to the object, depending on the object's type -- and in those
cases where I can't get a reference to the object by merely
mentioning it I will need to use explicit "give me a reference
to this, DON'T call it!" operators that aren't needed otherwise.
I feel this impacts the "first-classness" of functions (or
methods, or other callable objects) and the possibility of
interchanging objects smoothly. Therefore, to me, this specific
syntax difference is a serious black mark against Ruby -- but
I do understand why others would thing otherwise, even though
I could hardly disagree more vehemently with them:-).

Below the syntax, we get into some important differences in
elementary semantics -- for example, strings in Ruby are
mutable objects (like in C++), while in Python they are not
mutable (like in Java, or I believe C#). Again, people who
judge primarily by what they're already familiar with may
think this is a plus for Ruby (unless they're familiar with
Java or C#, of course:-). Me, I think immutable strings are
an excellent idea (and I'm not surprised that Java, independently
I think, reinvented that idea which was already in Python), though
I wouldn't mind having a "mutable string buffer" type as well
(and ideally one with better ease-of-use than Java's own
"string buffers"); and I don't give this judgment because of
familiarity -- before studying Java, apart from functional
programming languages where _all_ data are immutable, all the
languages I knew had mutable strings -- yet when I first saw
the immutable-string idea in Java (which I learned well before
I learned Python), it immediately struck me as excellent, a
very good fit for the reference-semantics of a higher level
programming language (as opposed to the value-semantics that
fit best with languages closer to the machine and farther from
applications, such as C) with strings as a first-class, built-in
(and pretty crucial) data type.

Ruby does have some advantages in elementary semantics -- for
example, the removal of Python's "lists vs tuples" exceedingly
subtle distinction. But mostly the score (as I keep it, with
simplicity a big plus and subtle, clever distinctions a notable
minus) is against Ruby (e.g., having both closed and half-open
intervals, with the notations a..b and a...b [anybody wants
to claim that it's _obvious_ which is which?-)], is silly --
IMHO, of course!). Again, people who consider having a lot of
similar but subtly different things at the core of a language
a PLUS, rather than a MINUS, will of course count these "the
other way around" from how I count them:-).

Don't be misled by these comparisons into thinking the two
languages are _very_ different, mind you. They aren't. But
if I'm asked to compare "capelli d'angelo" to "spaghettini",
after pointing out that these two kinds of pasta are just
about undistinguishable to anybody and interchangeable in any
dish you might want to prepare, I would then inevitably have
to move into microscopic examination of how the lengths and
diameters imperceptibly differ, how the ends of the strands
are tapered in one case and not in the other, and so on -- to
try and explain why I, personally, would rather have capelli
d'angelo as the pasta in any kind of broth, but would prefer
spaghettini as the pastasciutta to go with suitable sauces for
such long thin pasta forms (olive oil, minced garlic, minced
red peppers, and finely ground anchovies, for example - but if
you sliced the garlic and peppers instead of mincing them, then
you should choose the sounder body of spaghetti rather than the
thinner evanescence of spaghettini, and would be well advised
to forego the achoview and add instead some fresh spring basil
[or even -- I'm a heretic...! -- light mint...] leaves -- at
the very last moment before serving the dish). Ooops, sorry,
it shows that I'm traveling abroad and haven't had pasta for
a while, I guess. But the analogy is still pretty good!-)

So, back to Python and Ruby, we come to the two biggies (in
terms of language proper -- leaving the libraries, and other
important ancillaries such as tools and environments, how to
embed/extend each language, etc, etc, out of it for now -- they
wouldn't apply to all IMPLEMENTATIONS of each language anyway,
e.g., Jython vs Classic Python being two implementations of
the Python language!):

1. Ruby's iterators and codeblocks vs Python's iterators
and generators;

2. Ruby's TOTAL, unbridled "dynamicity", including the ability
to "reopen" any existing class, including all built-in ones,
and change its behavior at run-time -- vs Python's vast but
_bounded_ dynamicity, which never changes the behavior of
existing built-in classes and their instances.

Personally, I consider [1] a wash (the differences are so
deep that I could easily see people hating either approach
and revering the other, but on MY personal scales the pluses
and minuses just about even up); and [2] a crucial issue --
one that makes Ruby much more suitable for "tinkering", BUT
Python equally more suitable for use in large production
applications. It's funny, in a way, because both languages
are so MUCH more dynamic than most others, that in the end
the key difference between them from my POV should hinge on
that -- that Ruby "goes to eleven" in this regard (the
reference here is to "Spinal Tap", of course). In Ruby,
there are no limits to my creativity -- if I decide that
all string comparisons must become case-insensitive, _I CAN
DO THAT_! I.e., I can dynamically alter the built-in string
class so that
a = "Hello World"
b = "hello world"
if a == b
print "equal!\n"
else
print "different!\n"
end
WILL print "equal". In python, there is NO way I can do
that. For the purposes of metaprogramming, implementing
experimental frameworks, and the like, this amazing dynamic
ability of Ruby is _extremely_ appealing. BUT -- if we're
talking about large applications, developed by many people
and maintained by even more, including all kinds of libraries
from diverse sources, and needing to go into production in
client sites... well, I don't WANT a language that is QUITE
so dynamic, thank you very much. I loathe the very idea of
some library unwittingly breaking other unrelated ones that
rely on those strings being different -- that's the kind of
deep and deeply hidden "channel", between pieces of code that
LOOK separate and SHOULD BE separate, that spells d-e-a-t-h
in large-scale programming. By letting any module affect the
behavior of any other "covertly", the ability to mutate the
semantics of built-in types is just a BAD idea for production
application programming, just as it's cool for tinkering.

If I had to use Ruby for such a large application, I would
try to rely on coding-style restrictions, lots of tests (to
be rerun whenever ANYTHING changes -- even what should be
totally unrelated...), and the like, to prohibit use of this
language feature. But NOT having the feature in the first
place is even better, in my opinion -- just as Python itself
would be an even better language for application programming
if a certain number of built-ins could be "nailed down", so
I KNEW that, e.g., len("ciao") is 4 (rather than having to
worry subliminally about whether somebody's changed the
binding of name 'len' in the __builtins__ module...). I do
hope that eventually Python does "nail down" its built-ins.

But the problem's minor, since rebinding built-ins is quite
a deprecated as well as a rare practice in Python. In Ruby,
it strikes me as major -- just like the _too powerful_ macro
facilities of other languages (such as, say, Dylan) present
similar risks in my own opinion (I do hope that Python never
gets such a powerful macro system, no matter the allure of
"letting people define their own domain-specific little
languages embedded in the language itself" -- it would, IMHO,
impair Python's wonderful usefulness for application
programming, by presenting an "attractive nuisance" to the
would-be tinkerer who lurks in every programmer's heart...).

Alex Martelli

No comments:

Post a Comment