Tim gives mad props. My favorite bit:
Maybe the single biggest advantage is readability. Once you’ve got over the hump of the block/yield idiom, I find that a chunk of Ruby code shouts its meaning out louder and clearer than any other language. Anything that increases maintainability is a pearl beyond price. [emphasis mine]
In theory, Python ought to do better, lacking all those silly end statements cluttering up the screen. But in practice, when I look at Python code I find my eyes distracted by a barrage of underscores and double-quote marks. Typography is an important component of human communication, and Ruby’s, on balance, is cleaner.
Scattered Thoughts About Ruby vs. Python, Mostly Inconclusive
On Indentation
As someone who uses Python in his day job, and Ruby whenever I can fit it in (for very small values of t), I have to agree. Python can be readable, and having blocks be delimited by indention levels is not always a bad thing. But it can get rather hairy when lines wrap, or when you try to make lines fit neatly in a terminal window using the ‘\’ line continuation marker. Then your nice indentation gets a little harder to “just see”.
Maps and Filters: a woefully-incomplete case study
One thing I do about Python is list comprehensions, i.e. taking a list or array, and then mapping each element in it to a function. Here’s an example:
n = [1, 2, 3, 4] p = [ x*2 for x in n ]
Pythonistas will note that the list comprehension is a shorthand for the map built-in function:
p = map(lambda x: x*2, n)
As much as I like list comprehensions, I find myself agreeing that Ruby is a bit more descriptive (and easier to read) than Python. After six months of using Python in my day job, I still find lambdas in Python to be syntactically icky.
Even though Ruby doesn’t have list comprehensions, it’s version of Array.map is easier to read then both in my opinion:
n = [1, 2, 3, 4]
p = n.map { |x| x*2 }
You can make the Ruby version a bit more verbose by using do ... end instead of the curly braces:
p = n.map do |x| x*2 end
Most Rubyists would prefer the former version over the latter, for brevity’s sake.
Python also gives us filter to filter an enumerable object, but again, you have to use lambda unless you’ve defined a function elsewhere:
f = filter(lambda x: x>2, n)
Ruby gives us Array.select:
f = n.select { |x| x>2 }
Conversely, there is also Array.reject, which does the opposite of Array.accept:
g = n.reject { |x| x>2 }
Logically Speaking
One last thing. Suppose you want to do the union of two arrays. In Python, you have to make the lists sets by casting (ugh) and, if you want to keep the mutable list, you have to recast it back to a list (double ugh).
a = ['foo', 'bar', 'baz'] b = ['quux', 'bar'] c = list(set(a) | set(b))
In Ruby, you get the logical operations on Arrays for free:
c = a | b
That’s it; either way, you get ['foo', 'bar', 'baz', 'quux'] (although not necessarily in that order).
Conclusion
At the end of the day, I’m happy using either language over pretty much anything else.
(But I not so secretly heart Ruby.)
UPDATE: Silly me, you can use a list comprehension in Python to save yourself a lambda for filter:
[ x*2 for x in n if x>2 ]
Thanks to my coworkers for reminding me of this.
UPDATE 2: Duh. Array.select, not Array.accept.