
Why Ruby is not my favorite language - vladimir
http://blog.codeslower.com/2008/10/Why-Ruby-is-Not-My-Favorite-Language
======
blasdel
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:

    
    
      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

~~~
mhartl
_I had a great question in a job interview yesterday_

For what it's worth, this has recently become a 'standard' interview question
for developers. I predict that people will start game it by having a canned
response, thereby rendering it virtually useless---just like all other
standard interview questions.

~~~
jamesbritt
"For what it's worth, this has recently become a 'standard' interview question
for developers."

I used to ask interviewees to discuss what they didn't like about their
favorite language. If they had a hard time finding stuff to criticize, there
was a good chance they didn't really know the language. or were not
particularly critical developers.

~~~
mhartl
Right, that's why it was _initially_ useful. Now that lots of people use the
question, though, even mediocre developers will make sure to come to the
interview with a list of criticisms of their favorite language.

~~~
jamesbritt
"... even mediocre developers will make sure to come to the interview with a
list of criticisms of their favorite language."

Which is fine if, when pressed, they can back up what they say. The question
(like most good interview questions) is largely an excuse to help guide a
conversation and some exploration to avoid canned responses.

------
Locke
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:

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 _add_ something without noticeably
changing the original behavior.

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.

I've been writing ruby software for several years now, and there are
definitely libraries that annoy me ( _ahem_ activesupport), but the utility of
having open classes has _far_ outweighed any of the negatives. Let's face it,
in any programming ecology there are going to be some _awful_ libraries. Bad
programmers don't need open classes to do damage.

------
lsb
It's a fundamental problem of language design.

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.

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.

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.

------
KirinDave
This argument is totally spurious. You can find terrible, brain-bending
libraries in every language. Why is ruby a write-off because of ActiveRecord?

Seems like the implicit argument is that Root-Object modifications are
unmaintainable. But the reality is that assertion really isn't backed up
anywhere.

There are lots of valid complaints against Ruby. This is not one of them.

~~~
scott_s
He said "Ruby is a great language," but not his favorite language. I don't
consider that writing-off the language.

~~~
KirinDave
It just seems like he's claiming citing something and claiming it's a mess,
but there's no real evidence that it is a problem.

------
ruby_roo
So there's this Ruby tool called RDoc that will introspect your project and
tell you all about what's inside. Problem solved?

Here, look at RDoc's features (from the RDoc website):

\--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.

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?

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]).

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.

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).

------
Tichy
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.

That is just one example, but I suppose it is more attitude than necessity
that makes the difference here...

------
charlesju
So what's the alternative?

~~~
mdasen
Well, the alternative could be more like Python.

Python supports both object methods and functions. Ruby only supports object
methods. However, Ruby does allow you to define methods outside of an object -
these become methods of the Object class. As such, any methods defined like
functions become changes to all objects since they inherit from Object.

Python is also very explicit about its namespacing and imports. In Python, you
should always be able to know where any name you're using is coming from. In
the example from the article, 'to_yaml' is added by requiring rubygems. That
isn't so apparent (in the way that 'gem' being added by requiring rubygems
would be apparent). Names are reused all the time. Names sometimes aren't
related to their package in an apparent way.

With Python, you have three options (one of which Python programmers will flog
you for): from package import name, name2 import package from package import *
-- should really only be used in an interactive python shell and not in
programs

In the first one, you could then call name(something) or name2(something). BUT
you can see exactly where those names are coming from -- package. Unlike
to_yaml which could come from wherever, it's explicit that it comes from
'package'. In the second one, you can do package.name(something) and the like.
Similarly, you can see that it comes from 'package'.

Ruby is really flexible, but I would argue that the author is correct in
assessing that the ability to modify all objects implicitly is a bad thing.

~~~
timr
Also, information hiding is rumored to be important in real software. Ruby
gives you the ability to nominally "hide" data, but it's trivially easy for
any later programmer to violate the encapsulation. It's DHINO programming --
Data Hiding In Name Only.

Not only isn't this considered a bad idea in the Ruby world, but it's actually
a _common_ technique. Use a third-party library, and you may well be re-
writing core parts of the language. Sound good? _You can't prevent it._

I like parts of Ruby; it's a fun language. But the author is right -- it's not
a language for large projects, or projects with more than a few programmers.
My alternative to Ruby would allow the fast-and-loose stuff that makes Ruby
fun, but also give you a way to make classes immutable and guarantee data-
hiding and encapsulation when you need to do real software engineering.

~~~
davidw
I don't like the "real software engineering is big heavy Java projects" thing
(aka "bondage and discipline"). Plenty of "real software engineering" has been
done to great effect with dynamic languages.

Here's a random idea: rather than strict locks, perhaps transparency would be
a good approach. Load up a third party library, and you get informed that it's
fiddling with things, and can then find out what. Maybe it really does need to
fiddle with things. Or maybe in a given situation, fiddling with things is the
most efficient way of accomplishing something.

~~~
timr
_"rather than strict locks, perhaps transparency would be a good approach"_

Transparency is a great, but you still need rules when you're working with any
code that's bigger than what you can hold in your head at any given time.
Doubly so when you're working with a team.

Programming in a team is hard in the same way that taking care of a room full
of toddlers is hard -- obviously, you want everything out in the open, but you
also want to hide the sharp objects, put caps over things that can shock, and
otherwise make the big, transparent room as soft and bouncy as possible. You
need locks on the cabinets full of poisonous chemicals. Obviously, the locks
_need_ to be open-able, but only in special situations, and certainly not by
nosy toddlers.

(Before you criticize me for being paternalistic, realize that I include
_myself_ in the "toddler" category. I much prefer code that's written in a
defensive style, because it's easier for me to maintain later on -- and that's
where any programmer spends the majority of his time. I've developed this
attitude because I know that I'm _stupid_ , not because I'm arrogant.)

~~~
Xichekolas
While I agree that writing code defensively is the way to go when a team is
involved and/or you plan to have to maintain the code for years, I don't think
it's the language's job to take away all the 'sharp objects'.

Programmers should be smart enough to know what is sharp and how to avoid it
when needed, and they should collaborate enough that no one can sneak through
sloppy code.

I'd rather have the ability to do certain things and rarely use it than not
have the ability at all. If other programmers are constantly doing really dumb
things, don't use their code in your projects.

~~~
timr
Even in strict languages, there's rarely anything that _absolutely prevents_
you from doing what you need to do; they just make it harder to do bad things
accidentally. Languages like Ruby actually make it harder to do things
_correctly_ , and constantly tempt you with hideous shortcuts.

Again, I view programming teams as groups of nosy toddlers. Thus, any sentence
beginning with "programmers _should_ be..." is wrong by definition.
Programmers are people, and people make mistakes. People also get lazy, try to
take shortcuts, and therefore make even more mistakes. The way that people
minimize mistakes is by setting up systems that make it harder to do wrong
things. This is a fundamental tenet of engineering.

