What’s Not Necessarily Wrong With Ruby

- - posted in Ancient Archives

Bitwise introduces ‘What‚Äôs Wrong With Ruby?’ with

Matthew Huntbach takes a long hard look at the coolest language on the planet and is distinctly under impressed by what he sees…

That introduction has more than a slight aroma of flamebait. In the actual article Mr Huntbach concludes:

Despite what I’ve written above, I didn’t find Ruby horrible. If I needed to use a scripting language, it’s the one I would now use. It’s cleaner than Perl, and I like its syntax better than Python. Its object-based nature works for me: object-orientation is not the silver bullet, but it is a better abstraction for managing complexity and modelling things than anything else we have. It has picked up some useful aspects from functional programming as well and put them into a language whose ability to handle interaction between stateful objects makes it more practical than pure functional programming (still to me, real elegance, but of an infuriating kind). But it isn’t as revolutionary or as cool as its advocates suppose.

I can’t disagree with that at all. Ruby is generating a lot of hype because it can trigger great enthusiasm from the hordes of recently converted PHP and Java programmers. Ruby can also support trendy new paradigms like meta-programing, BDD and domain-specific languages with ease, so tends to get caught up in all the Cool New Development trends. It’s zeitgeisty!

Skip over the academic language snobbery (that’s a whole topic in itself…) and there’s nothing really objectionable about the article at all. I find the description of a conference full of programing academics quivering with confusion about the ungodly goings on the real world rather amusing. People are using scripting languages! Oh my goodness! Why won’t they listen to us?

I disagree with Matthew Huntbach’s criticism of Ruby’s array handling as unintuitive, however.

I‚Äôll give just a couple of examples. In Ruby, if a is [1,2,3] and b is [10,20,30], then a+b is [1,2,3,10,20,30]. Why not [11,22,33], which Tim Sweeney in an earlier article suggests “intuitively makes sense”? What does a[x,y] (when a is a two-dimensional array) mean in Ruby? Not what I first supposed it might mean from other languages (otherwise a[x][y]), or even what I then thought it might mean (otherwise a[x..y]).

The plus sign has this functionality for Ruby arrays (all operators are just object methods in Ruby):

[1, 2, 3] + [4, 5, 6] => [1, 2, 3, 4, 5, 6] [1, 2, 3, 4, 5, 6] - [3, 1, 6] => [2, 4, 5] [ 1, 2, 3 ] * 3 => [1, 2, 3, 1, 2, 3, 1, 2, 3] Ruby’s array is a list that can contain any mix of objects. The plus operator is a method acting on the list object, not its contents. The least surprising results of adding two lists is a longer list, hence the default, sugary behaviour of plus.

Matthew Huntbach would get the behaviour he wanted by using the correct classes, Vector and Matrix.

a = Vector[1, 2, 3] b = Vector[4, 5, 6] a + b => [5, 7, 9] If you want to apply a method to the contents of an object, use a map or collection method. Ruby excels at this. One of the reasons Ruby makes me happy is that its array handling is so much more convenient than Perl’s.

Ruby’s behaviour will not always be “intuitive” if you’ve spent years working with C based languages, but I think this more often just down to unlearning old habits than flaws in the language itself. Ruby quite deliberately dumps the non-OOP baggage of C based languages. Ruby was written as a replacement for Perl but is not conceptually descended from Perl, or from C. Its purpose was modelled on Perl, but it’s ancestry is more closely linked to Lisp and Smalltalk.

Although I think Ruby succeeded in following the principle of least surprise in most cases its fundamental differences from the C based languages do cause a few points of confusion. My own favourite is Ruby’s evaluation of “truthiness”.

In most C-based languages 0, “”, undefined are false. Anything else is true.

$result = 0; print "Hello" if $result; => In Ruby only Falseclass and Nilclass are false. Any other defined object is true, including 0 and empty strings.

result = 0 print "Hello" if result => "hello" (Both approaches are justifiable but I’m now happier with Ruby’s approach. 0 and “” are still, present valid data. In my contrived example above 0 is still a result)

Another gotcha is that every named variable is effectively containing a reference to the actual object. By default assignment copies the reference, not the object.

a = "HELLO" b = a a => "HELLO" b => "HELLO"

a.downcase! a => 'hello' b => 'hello' This is rarely a problem but occasional use of .dup is required.

Update: If you want to read more interesting responses to the Bitwise article then take a look at Why’s admission that yes, he is what’s wrong with Ruby, and make sure you read the comments.

This all coming from a guy whose current interest is the Aldwych programming language.

Ouch.

Update: Storm in teacup continues at Bitwise!