I wasn't going to post this as an answer, but Xeoncross asked me to, so here we go:
(Sidenote: if someone could fix the markdown issue in the little code example, I'd appreciate it.)
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!):
Ruby's iterators and codeblocks vs Python's iterators and generators;
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