1. Why I’ve Avoided the Ruby Culture

    First, read this rant. Now, let me summarize: Ruby culture advocates changing the way pieces of the language work in a global way (sometimes known as monkey patching). In this particular case, two different packages (gems) have their own nifty (incompatible) implementations of the sum method of the Array object. The built-in, language-wide Array object. The comments on the Hacker News thread are especially enlightening as to why this is a bad thing.

    What’s interesting is that, in Python, you can also implement the same sort of mischief, but no one does despite the fact that in Python the scoping/privacy rules center around the idea that “we’re all adults here” (i.e. nothing’s private or final). In fact, while Rubyists seem to embrace monkey patching, Pythonistas seem to abhor the very idea except in very limited, necessary cases.

    Why the difference in culture? I would theorize that it has to do with Python’s BDFL (Guido van Rossum). Specifically, in designing Python, Guido has imparted many of his own programming sensibilities into the language design. In Python, there’s generally one obvious way to do something and in most cases, the less obvious ways are also less efficient/correct/maintainable. In contrast, Ruby’s creator Matz seemed to design from the many ways to do one thing philosophy (see Perl). But it’s more complicated that just this simple fact.

    One thing about language design that’s not widely talked about is that there are two distinct parts. Syntax is the part most people concentrate on because syntax is concrete. It’s easy to learn and understand pure syntax. For example, Lisp uses prefix notation and parenthesis as separators. Do you now understand Lisp? Nope. That’s because of the second, less visible and less talked about part of language design: the shared assumptions of the language. These are the ideas that hold the language together that aren’t part of the syntax, but are part of the language definition, sometimes implemented by the very language we are attempting to describe - Lisp is a great example of this. As a a brief aside: I have a pet theory that language power/versatility can be characterized by the ratio of shared assumptions to syntax - again think Lisp.

    Python’s shared assumptions are an interesting, and oft overlooked part of the language design - perhaps because they are in many cases rather transparent. I believe this is intentional. The language design as a whole nudges developers away from doing potentially dangerous things by giving them more attractive safe alternatives. Ruby, on the other hand (I’m not a Ruby expert, please don’t crucify me) seems to throw a bunch of options at the programmer and hope for the best. With increased freedom comes increased restraint, and I have a feeling many of the new Ruby converts have been living in a box for so long (i.e. Java) that they are still figuring out that just because you can do something doesn’t mean you should.

    The net result is that in Ruby, where all options are equal and restraint is likely somewhat lacking, we end up with a bunch of really clever solutions (and you know what Kernighan says about clever code). That isn’t to say that Ruby isn’t a great tool - it is, and probably ranks a bit higher on my power scale than Python, but when the community embraces practices like monkey patching, it makes me wonder if Ruby can survive its culture.