I had a great question in a job interview yesterday: "What do you like least about your least favorite programming language?". I picked Ruby as my least favorite, as there's not many languages out there that undermine themselves so totally (I may not want to program in basic, but it does what it says on the tin). Here's my answer:<p><pre><code> Matz's decision-making process
He tries to make Ruby be all things to all people
Lots of confusing sugar and overloading baked in
I much prefer Guido's hard pragmatism
The panoply of function types: Methods, Blocks, Procs, Lambdas
All intertwined and yielding into one another.
I love that in Python there is only one:
Objects with a __call__ method, defined metacircularly.
The culture of adding/overloading methods on base classes
Many gems do this en masse, and there are a lot of low-quality gems
Especially disastrous because it's unscoped, and infects the whole process
For a language with four scoping sigils it sure screws up scope a lot
The Matz Ruby Implementation
The opposite of turtles-all-the-way-down (Smalltalk crushed beneath Perl)
It punishes you for taking advantage of Ruby's strengths
The standard library is written almost entirely in C
It doesn't use Ruby message dispatch to call other C code.
That means that if you overload a built-in, other built-ins won't use it
Anything fiddly that's not written in C will be dog slow</code></pre>
Another (old?) rant about open classes aka "monkey patching". There's a lot of fear and hand wringing over open classes. It's certainly a language feature that can be abused, but it's also incredibly useful. There are things you can do to be safe:<p>Check for the existence of methods before adding them. Don't overwrite existing standard lib methods. If you do overwrite one, alias it, call the alias from your replacement which should <i>add</i> something without noticeably changing the original behavior.<p>If you write unit tests, it shouldn't be too difficult to detect that a library you depend on has changed the behavior of a standard method in an unacceptable way. I've encountered collisions like this, maybe, a handful of times and each time finding and resolving the problem was not difficult.<p>I've been writing ruby software for several years now, and there are definitely libraries that annoy me (<i>ahem</i> activesupport), but the utility of having open classes has <i>far</i> outweighed any of the negatives. Let's face it, in any programming ecology there are going to be some <i>awful</i> libraries. Bad programmers don't need open classes to do damage.
It's a fundamental problem of language design.<p>In Lisp, extending the built-in functions is trivial, so lots of people built Lisp up into the language to solve their problem in, and Ruby makes it easy to do the same. Rails is extends the language, and some people like it. Even the JSON gem does -- when you do "require 'json'", you give arrays the power to convert themselves to json strings. Ruby lets you convert arrays to Ruby-evallable strings, so it's natural to convert them to JSON-parseable strings.<p>So, do you do what Java does, in making the String class final? Languages only exist for people who speak them, so you need to gauge the social aspects whenever you choose a language. Perhaps Java means that your bozo coworker won't trample your toes. Perhaps Haskell means that you can import just as much as you want. That's ultimately your call.<p>There are lots of valid complaints about Ruby 1.8: the syntax can be baroque, the scoping rules have too many gotchas, they're (thinking of) taking out continuations in the next version, the VM is dog-slow. But 200 methods on an object is small fries in comparison.
This argument is totally spurious. You can find terrible, brain-bending libraries in every language. Why is ruby a write-off because of ActiveRecord?<p>Seems like the implicit argument is that Root-Object modifications are unmaintainable. But the reality is that assertion really isn't backed up anywhere.<p>There are lots of valid complaints against Ruby. This is not one of them.
So there's this Ruby tool called RDoc that will introspect your project and tell you all about what's inside. Problem solved?<p>Here, look at RDoc's features (from the RDoc website):<p>--Generates structured HTML documentation from Ruby source.
--Authomatically extracts class, module, method, and attribute definitions. These can be annonated using inline comments.
--Analyzes method visibility.
--Handles aliasing.
--Uses non-intrusive and implicit markup in the comments.
--Readers of the original source needn't know that it is marked up at all.<p>Or to come at this from a slightly different angle, don't Ruby's introspection powers provide a release valve for the problems the author is talking about?<p>Anyway, this is just another occasion to state the old adage, "With great power comes great responsibility." You don't have to crapify your Ruby projects if you don't want to. If you need to enforce clarity at all times, I see no better alternative than Python (which I think makes it a better candidate for scientific or math-intensive projects, MRI slowness aside [although I am curious about the implications of genetic algorithms + Ruby introspection]).<p>I do speculate that if you take two programmers of equal skill levels and give one Python and the other Ruby, the Rubyist can gain a productivity advantage over the Pythonista via judicious use of Ruby hackery. But this comes at a cost: it does require more thoughtfulness before execution. Maybe you don't want to think that hard, and that's a totally legitimate and respectable position. In the end, which of the two languages you choose will probably have more to do with personal workflow preferences or project management ideologies.<p>In the case of Rails, yes, it hacks in a DSL and extends Ruby classes, but Rails relies heavily on conventions and things being put in designated areas. It's therefore hard to get lost in a Rails project unless you really have no respect for the conventions (in which case, it doesn't matter what language or framework you're using).
I wonder how much of the monkey patching is really necessary? Recently I have looked at Rails again, and in prototype (Javascript) "function" is monkey patched to have a bind method, so you can write function.bind(object). In Mochikit you have a method bind(function, object). It is not even longer to type. Mochikit is not monkey patched - although admittedly "bind" is in the global scope. Mochikit can prevent the global scope optionally, though.<p>That is just one example, but I suppose it is more attitude than necessity that makes the difference here...