Search This Blog

Tech Book Face Off: The Ruby Programming Language Vs. Eloquent Ruby

I feel like I'm coming a little late to this party. The excitement over Ruby seems to have peaked years ago, and now all the talk is about things like Scala and Node.js. I don't mind, though. I figure it's never too late to learn a new language, especially one as beautiful as Ruby. Besides, Ruby is in very active development, with the 2.0 version of the language having been released this February, and a lively and helpful community to support it. I would say that if you've been putting off learning Ruby, now is a great time to finally take the plunge, and here are two books to help you on your way.

The Ruby Programming Language front cover VS. Eloquent Ruby front cover

The Ruby Programming Language


This book was written by the same David Flanagan that wrote the excellent JavaScript: The Definitive Guide that I reviewed months ago, and it was co-authored by the inventor of Ruby, Yukihiro "Matz" Matsumoto. It was written in a similar no-frills, straight-to-the-point style that I once again enjoyed and appreciated immensely. When learning the ropes in a new programming language, I want to see a well organized presentation of the features with clear, concise examples and crisp, direct explanations of those features. No games or gimics, please; just the facts. This book delivers exactly to those expectations.

Overall, I would say the book was very easy to read and understand. That could just as easily be said about the Ruby language itself, of course. The flexible syntax and the ability to write programs that read more like natural language than most other programming languages is really appealing. While playing around with solving some basic algorithmic problems in Ruby, I was impressed with how easy it was to express the solutions in the language in nearly the same way that I was thinking about solving them in my head. And Flanagan and Matz did a good job of showing all of the language features in a way that I could pick up quickly and use right away. They methodically explained all of the features and concepts in a nice, logical order.

That is not to say that there weren't a few rough spots. Things got a bit hairy with enumerators and external iterators, and then again with class variables and class instance variables. This was only partially because these concepts didn't click for me right away. After backing up and reviewing those sections, I understood the syntax and what was going on well enough. The main issue with enumerators is that I don't really see when you would want to use them, but I suppose being aware that they exist is the important thing at this point. Beyond that it's a case of "you'll know it when you need it."

With class variables and class instance variables the problem was more of knowing when to use one instead of the other, and Flanagan and Matz didn't get into that much at all. It would have been out of character with the rest of the book, but that's alright because the subject of when and how to use Ruby's language features was pretty much the next book's reason for being. As for The Ruby Programming Language, it was a great introduction and overview of Ruby for an experienced programmer. I highly recommend it to any programmer ready to learn a new and fun language.

Eloquent Ruby


Russ Olsen goes in a completely different direction with Eloquent Ruby. I'm not sure if you would be able to learn Ruby if this book was your only resource. At the very least you would need to refer to the documentation quite a bit when you were starting out. But this book will teach you how to use Ruby to solve real problems and why you would write programs certain ways to be more effective. In short Olsen teaches you how to write idiomatic Ruby.

I thoroughly enjoyed reading this book. I don't think I've had this much fun reading a programming language book since, well, ever. It was like reading The Pragmatic Programmer, but for a programming language instead of general programming practices and processes. Olsen was conversational and engaging, and he really helped me understand how to write good Ruby code. He covered everything from the use of different control structures to writing specs, the use of class instance variables, the various uses of method_missing, creating self-modifying classes, and implementing DSLs (domain-specific languages).

The book is packed with all kinds of useful information in a nice, readable format. Olsen starts out with more basic, general concepts like code formatting and comment style and moves progressively into more complex topics, culminating in a series of excellent chapters on metaprogramming and DSLs. Each chapter addresses one self-contained topic about Ruby programming and includes sections on how to avoid common errors and pitfalls, and what real implementations of the topic under discussion look like "in the wild." This format ends up working really well, and I found the pace extremely easy to follow. It was very understandable, and I learned a ton.

I do have a few quibbles about parts of the book, though. Sometimes his reasons for things like commenting lightly or writing short methods seemed a little weak. It's not that I disagreed with his recommendations. In fact, I mostly agree with him, especially about restricting comments and letting the code speak for itself. But I thought he drew out his arguments a bit too long and included points that ended up sounding like, "You should do it this way because that's the way the Ruby community does it." I found myself disagreeing with some these minor points even though I agreed with the overall premise, and that was distracting. His arguments would have been stronger if he had tightened them up a bit and left out the weaker claims.

Another minor annoyance was the footnotes. I really don't understand why he felt the need to include these when they were nearly entirely useless to the reader. Every time I jumped to a footnote hoping for a little extra insight, and instead was confronted with flippant comments like "Try as we might" or "Yet," (seriously!) I was reminded that I really shouldn't be wasting my time with these footnotes. I still read them all because I couldn't help myself, but I guarantee that none of them were essential. Sure, there were a few clarifying points, but if they were so important to include, they should have been integrated into the text instead of cordoned off as footnotes. However, I didn't see any of them as critical, and you're really not missing anything by skipping them. Trust me, I read them so you don't have to.

Thankfully, those two minor drawbacks can be easily ignored, and the book doesn't really suffer for them. There is so much good material in there that I highly recommend Eloquent Ruby to every Rubyist. It will help take your programming to the next level, and give you plenty of ideas for how to write better Ruby code.

Ruby: The Language


So what about the Ruby language itself? I have to say that it is great fun to program in it. For someone who has spent more than a decade writing mostly in C++, writing in Ruby gave me the distinct feeling of being set free. It also pleasantly reminded me of my early programming experiences with Logo with many moments of youthful excitement and awe - as in, "wow, you mean you can really do that? Awesome!"

I'd like to do a rundown of some of the basic features of Ruby compared to C++, similar to what I did in my JavaScript book review, to show you how Ruby compresses code. Let's start out again with a few simple variable declarations in C++:
int samples[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
int sum = 0;
double mean = 0.0;
And the same declarations in Ruby:
samples = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
sum = 0;
mean = 0.0;
Nice! Ruby doesn't even need the 'var' keyword in its variable declarations, like JavaScript does. On a variable assignment, it searches for the variable symbol, and if it doesn't find it, Ruby conjures it into existence right there. So easy.

Now let's go a bit further and do the calculations hinted at by those variable names. First in C++:
sz = sizeof(samples)/sizeof(samples[0]);
for(int i = 0; i < sz; i++) {
  sum += samples[i];
}
mean = sum/static_cast<float>(sz);
And then in Ruby:
sum = samples.inject(:+)
mean = sum/samples.size.to_f
Seriously, that is not even funny. Look at how clean that is! You can actually inject an operator into a collection and it just works. 

Alright, let's say you want to create a quick object to hold some data on your pets. In C++ you'd have to at least create a struct and instantiate it. That would look something like this:
struct Pet {
  string name;
  string type;
  string breed;
  int age;
  double weight;
}

Pet myPet = {"Twitch", "cat", "Siamese", 10, 8.4};
And then there's Ruby:
myPet = {
  name: "Twitch", 
  type: "cat", 
  breed: "Siamese", 
  age: 10, 
  weight: 8.4
}
This isn't an object literal like it is in JavaScript. It's actually a hash, but since objects are implemented as hashes in JavaScript, this is basically the same thing in Ruby. Now let's say we wanted to make the pet more permanent as a class. In C++ you might do this:
class Pet {
private:
  string _name;
  string _type;
  string _breed;
  int _age;
  double _weight;
public:
  Pet(string name, string type, string breed, 
      int age, double weight) {
    _name = name;
    _type = type;
    _breed = breed;
    _age = age;
    _weight = weight;
  }
}

Pet myPet = new Pet("Twitch", "cat", "Siamese", 10, 8.4);
You might want to include setter and getter methods for any of the members (class variables) that you'd want to change later, but I'll omit those for brevity's sake. I'm also not including any error checking code that would be required, like making sure the age and weight are within reasonable bounds. Now here's the equivalent Ruby:

class Pet
  def initialize(name, type, breed, age, weight)
    @name = name
    @type = type

    @breed = breed
    @age = age
    @weight = weight
  end
end
myPet = Pet.new("Twitch", "cat", "Siamese", 10, 8.4);
The '@' symbol marks a variable as an instance variable, and they come into being on the spot, just like other variables do. The admittedly small amount of Ruby I have shown here is fairly comparable to JavaScript, but as you get further into Ruby, you find that it goes well beyond JavaScript in its ability to express programs cleanly and compactly, and C++ is left in the dust. Yes, C++ definitely has its uses, and dynamic languages can't hope to compete with it on speed. But Ruby has an enjoyment factor in its expressiveness that clearly outshines C++.

So About Those Books


It's difficult to say whether The Ruby Programming Language or Eloquent Ruby is a better book. They are both excellent and serve distinctly different purposes. If you want to get started in Ruby quickly, and you already have a programming background, then you can read the first half of The Ruby Programming Language and be good to go. If you're already familiar with Ruby, but you're unsure of the best way to use certain language features or want to learn more idiomatic ways of solving problems in Ruby, then Eloquent Ruby is the book for you.

The Ruby Programming Language makes an excellent reference when you need to look something up, and Eloquent Ruby is a great read for when you want to improve your programming style. They each have their strengths and are targeted for different audiences, or the same audience at different points on the Ruby learning curve. They make a great combination, but one thing neither of them is good for is the novice programmer. If you're starting out learning to program, I think Ruby is a great first language to learn because it is so clean, flexible, and accessible, but these two books are not going to introduce Ruby in a way that a beginner can use. For the aspiring programmer, you'll have to find resources that introduce things at a slower and more careful pace.

For the rest of you programmers out there with a desire to learn or improve programming in Ruby, these two books are definitely worth checking out. They've certainly earned a spot in my library.

No comments:

Post a Comment