Why I Chose Ruby over Python
This year I spent a bit of time playing with Python, after having mostly ignored it since 2005 when was learning it originally. I did like Python back then, but a few years afterwards I discovered Ruby and quickly focused my entire attention on it.
There were many (mostly small) reasons why I leaned towards Ruby back then and playing with Python now made me remember a few of them. I thought it might be interesting to write a bit about those, so here we go.
Disclaimer: This is not a rant and I know that:
- the things I prefer in Ruby over Python are super subjective
- for every thing that Ruby does “better” there’s something else that Python does better
So, treat this as an amusing personal account and nothing more than that.
Built-in functions
Probably the thing about Python that bothered me the most what stuff that would normally be methods are global functions (that often call some object methods internally). I’m referring to the likes of:
len
sum
pow
You can find the full list here.
I’m guessing the reason for this (as usual) is historical, but I much prefer the way Ruby does things.
E.g. str.length
instead of len(str)
or arr.sum
vs sum(arr)
.
Semantic indentation
At first I thought the semantic indentation used by Python is super cool, as it reduces a bit the typing one needs to do:
if a < b:
max = b
else:
max = a
In hindsight, however, I quickly realized that it also:
- makes things harder for tooling, as it can’t really rearrange indented code sections
- in editors you can’t have much in terms of auto-indenting as you type (as the editor can’t know when a block finishes without you outdenting explicitly)
One more thing - 4 spaces by default seems a tad too much to me, although that’s obviously debatable.
P.S. I feel obliged to admit I’m not a big fan of do/end
either and would have preferred {}
instead, but it is how it is.
The bool
type
I’m not a fan of Python’s bool
type as for me it’s a pretty weird duck:
bool
was added only in Python 2.3- it inherits from
int
True
andFalse
are essentially 1 and 0
I get how things ended up the way they are, but for me it’s not OK to be able to write code like True + 1
.
I’m also not a fan of treating empty collection literals as False
, although I definitely have less issues
with this than with 0 and 1.
To compare this with Ruby:
boolean
has nothing to do with numbers there- the only things are considered logically false are
false
andnil
This definitely resonates better with me.
Side note: Lately I’ve been playing a lot with languages like OCaml, F# and Rust, that’s why to me it now feels extra strange to have a boolean type that works like an integer type.
Ranges
I really like the range literals in Ruby:
1..n
(inclusive range)1...n
(exclusive range)
Python has the range
function that kind of gets the job done, but for whatever reason
it doesn’t have the option to mark something as inclusive range.
Definitely not a big deal, but one of the many small touches of Ruby’s syntax that I came to appreciate over time.
Naming conventions
Ruby predicates typically have names ending in ?
- e.g. even?
, odd?
, digit?
. This makes them
really easy to spot while reading some code. Python sticks to the more common convention of prefixing
such methods with is_
, has_
, etc and that’s fine. One thing that bothers me a bit is that often
there’s not spaces between the prefix and the rest of the name (e.g. str.isdigit?
), which doesn’t
read great in my opinion.
More importantly, in Ruby and Python it’s common to have destructive and
non-destructive versions of some methods. E.g. - arr.sort!
vs arr.sort
in
Ruby, and list.sort
vs sorted(list)
in Python.
I don’t know about you, but to me it seems that:
- Ruby encourages you to favor the non-destructive versions of the methods, unlike Python
- Ruby’s more consistent than Python
I’m guessing the reasons here are also historical.
Triple-quoted string literals
Multi-line text literals are common in many languages, but I’m not super fond of:
x = """a multi-line text
enclosed by
triple quotes
"""
Who thought that typing those would be easy?
It’s not that HEREDOCS in Ruby are great either, but I guess they are at least more common in various programming languages.
The million Python package managers
Ruby has rubygems
and bundler
. That’s it. Everyone uses them. Life is simple.
Things are a lot more complicated in the realm of Python where several different tools
have been in fashion over the years:
easy_install
pip
pipx
poetry
Now it seems that uv
might replace them all. Until something replaces uv
I guess…
Epilogue
And that’s a wrap. I’m guessing at this point most Rubyists reading this would probably agree with my perspective (shocking, right?) and most Pythonistas won’t. And that’s fine. I’m not trying to convince anyone that Ruby’s a better language than Python, I’m just sharing the story of how I ended up in team Ruby almost 20 years ago.
Back in the day I felt that Ruby’s syntax was more elegant and more consistent than Python’s, and today my sentiment is more or less the same. Don’t get me wrong, though - I like Python overall and enjoy using it occasionally. It just doesn’t make me as happy as Ruby does.
I’ve long written about my frustrations with Ruby, so it feels pretty good to write for once about the aspects of Ruby that I really enjoy. Keep hacking!
P.S. After writing this I realized I had already written a similar article 14 years ago, but I had totally forgotten about it! Oh, well…