Sunday, February 25, 2007

Brave New Ruby World

The first time I heard about ruby was at University about eight years ago when most of ruby's documentation was Japanese. Back than it was hard to find a good introduction to ruby and since I favor curly bracket languages for aesthetic reasons I decided to stick with perl.

Last week I gave ruby a new chance to enter my programming tools portfolio. I'm developing embedded C++ for a living and usually automate coupling of code and data by using scripts. Now the task was to write a script to parse some enums in header files which use a predefined layout for comments, parse the whole code base to check whether those codes are used consistently (> 100.000 LOC) and generate and check some XML files that define default configurations for the software product.

Most of the scripts we used in the past are written in perl, since python just lacks the convenience. But since I always have a problem building up data structures in perl and knew that this script required some heavy data structure building I wanted to give ruby a try. So I opened some ruby introductions and documentations in my browser and watched myself learning ruby.

I was impressed. The documentation is very good and I was able to write productive code right from the start. One interesting thing is that while I learned more about ruby the code I had already written didn't seem awkward. With ruby I was able to write nice and clean code right from the start. This is probably what Yukihiro meant when he said he tried to make ruby "natural".

Ruby adapted to my OO style beautifully. Writing new objects and building up data structures works like the language was tailored to my needs. The convenient regular expression handling methods (which include the good ol' $1 .. $n variables we know from perl) make string parsing as easy as in perl. And while I don't have any data available, the perceived performance is quite impressive - parsing our complete code base with multiple regular expressions just takes a couple of seconds. Ruby even provides a perl-compatible command line argument set for in-line editing that can be controlled via built-in variables (see the Ruby Language Reference Manual).

After working with ruby for some hours, I find it very attractive that you automatically stick to a functional programming style for most of the time while introducing imperative data manipulating statements where necessary. This makes programming a far less error prone experience.

But the ruby also shows some less shiny sides. During the first hours of using ruby I discovered some interface anomalies that are not made explicit. For example it took me some time to figure out the difference between the foreach and the each function. Now that I understood that foreach is parametrized by an additional layer of abstraction objects I really like the concept, but still the naming got me confused at first - for me for each is executed for each element, so what's the difference?

Talking about interfaces: I used ruby libxml for xml parsing and generation. Everything worked fine in linux, but I was not able to install ruby-libxml via gem on windows without compiling the code by myself. So I looked for a different xml library that is available in windows, too. I found REXML, but REXML and ruby-libxml are not interface compatible. In a statically typed language the compiler would have taken care of this, but in ruby I don't get errors until late at runtime. It's especially hard in such a case when the interfaces contain methods with the same names that do different things. But than again perhaps such a high level of interface coherence is only possible with integrated commercial libraries like Java and .Net.

All in all ruby has blow my mind and I'll use it as primary scripting language from this day on. If you are looking for a clean object oriented dynamically typed language with a nice functional touch give ruby a try.


  1. I had the same experience learning it. There were countless moments when I was surprised by how directly you can express yourself, but also a few cases when my immediate intuition was wrong, and I was surprised to find something different in the manual.

    The sweetest language, anyway.

  2. > In a statically typed language the compiler would have taken care of this, but in
    ruby I don't get errors until late at runtime.

    I've found that the compiler type-checking I usually depend on in static-typed languages is replaced by automated unit testing in loosely-typed languages.

    Check out RSpec for a good Ruby testing framework, and rely more on your own tests than the compiler's, which is a good idea anyway.

  3. Adam, this is true (in fact I plan writing a small article on exactly this topic), but if you just write a few hundred lines of script, you usually skip the TDD stuff ...
    I'm still wondering if type inference is possible in an imperative language. This would allow static type checking... But this is probably not possible if types can be altered at runtime (perhaps to some extend?)