I'll tell you why I like Ruby

Nov 15, 2005 12 comments

I was curious this afternoon if there happened to be a built-in function for summing an array in Ruby. There isn’t, because it’s trivial using other methods to get the job done, but I found out how easy it is to make one on my own.

Ruby coolness #1

In order to add this function to the Array class, I didn’t have to go searching for a source file tucked away in the filesystem somewhere. No, I can extend it right in my code where I wanted to use the function. class Array def sum self.inject(0) {|sum, x| sum + x} end end

And just like that, Ruby will tack my sum function in the class and I can use it like any other Array function now.

Ruby coolness #2

Since everything is an object in Ruby, I can take my new function and use it like this: puts [34,36,23].sum

And out spits 93. I love this language, this is what programming is all about: having fun, being intuitive, easily extensible, concise but readable syntax, and the list goes on. It took me about 10 minutes to figure this out. I spent longer trying to figure out the most efficient way to sum an array and settled on the inject function.

This functionality reminds me of the flexibility of lisp macros. Does the language not have something in it that you want? No problem, just write it yourself!

If you’re wondering why I didn’t just write

puts [34,36,23].inject(0) { |a, b| a+b }

then you missed the point of the article. Besides, for those unfamiliar with Ruby code, which method is going to be easier to understand what it’s trying to accomplish?

C uncoolness #452

Lets see how little fun it is to write this in another language that doesn’t provide close to the flexibility that the Ruby version does (ie. needing to pass the array size): #include <stdio.h> int sum(int a[], int n) { int total = 0, i; for(i = 0; i &lt; n; i++){ total += a[i]; } return total; } int main() { int a[3] = {34, 36, 23}; printf("%d\n", sum(a, 3)); return 0; }

Yuck!

12 comments


Random Rubyist said about 6 hours later:

For the benefit of Ruby newbies who stumble across this in JavaBlogs, here’s a quick explanation of that Ruby line.

self.inject(0) {|sum, value| sum + value}

First off, the method inject can be found in the Enumerable module, documented here: http://www.ruby-doc.org/core/classes/Enumerable.html#M001954

It allows you to loop through an array, building up an “accumulator value” as you go. When it’s done, the final value of this accumulator is returned. Very useful for combining array elements, whether by summing them, building up a pretty display string, whatever.

In this case, we’ve initialized the accumulator to 0 and named its corresponding block variable “sum”. For each element in the array, inject is going to call that code block (passing in sum and the current element value) and assign the result back to sum. When it’s done with the whole array, it will return sum.

Tom said about 10 hours later:

Um. I get scared of extending common classes. It’s a namespace issue. Say I’m clever, too, and I think sum is a good idea and say this:

class Array def sum total = 0 each {|a| total += a} total end end

Hopefully I got that right. My Ruby’s a bit shaky. So, anyway, if I put this in my general-purpose library, and you happen to include it in the wrong order, sorry for you. Now your program runs slower.

Worse would be if I had a bug or an entirely different idea of what “sum” should do. (Unlikely here, but what about all the cleverness of ”$()” in the Prototype javascript library. Easy to imagine someone else, like say Microsoft in their Atlas system, picking up the convention but making it incompatible.)

It shouldn’t be so easy to dig into a public namespace. I think C# extension methods (warning, currently vaporware) are safer here since they don’t really modify globals.

And except for the array length thing, the C example doesn’t look so bad. In most cases, there’s really not a big difference between “sum(array)” and “array.sum()” from a syntactic convenience point of view. And I probably even want a specific implementation, so who cares about it being overridable or not.

Sorry. I like Ruby in many ways, but I still think this is a bad idea.

Tom said about 11 hours later:

Of course, C has its own global namespace problems, but many other more recent mainstream systems (like C++, Java, and C#) don’t tend to suffer the same thing.

Random Rubyist said about 16 hours later:

IMO, a better example of cool add-on functionality would be Rails’s FixNum and Time extensions.

In Java:

Calendar c = Calendar.getInstance();
c.add(Calendar.YEAR, -18)
Date d = c.getTime();

In Ruby:

d = 18.years.ago

:)

PJ Hyett said about 16 hours later:

Yes, that is also quite awesome.

aaa said about 17 hours later:

puts [34,36,23].inject(0){|a, b| a+b}

this is absolutely horrible. You are a student right?

For the date example.. who stops you writing a yearAgo(int years) method?

PJ Hyett said about 20 hours later:

My favorite commenter, aaa, I was wondering what took you so long to say something. I was beginning to worry. You and I both know you dislike anything that isn’t Java so I’ll spare you any sort of further explanation.

Tom said about 21 hours later:

On the other hand, I like all kinds of things that aren’t Java, and I think Ruby blocks are great in addition to other aspects of the language. And if you knew me, you’d hear me complain about Java almost every day. I’d like to get a response. I’m genuinely looking for one. My concern about namespaces still holds. But I haven’t heard much uproar on this topic. Do you ever run across issues with this, or is there some part of the system that makes such collisions unlikely.

I’ve done more JavaScript than Ruby, and I think the main thing that prevents me from seeing more of this problem is the present scarcity of reuse of 3rd party libraries. But I’ve had a chance to see some namespace collision problems anyway, and reuse of 3rd party JS seems to be on the rise.

Is this really never an issue in Ruby? If not, why not?

Tom said about 21 hours later:

In relation to 3rd party libraries, I was referring to the contrast between Ruby and JS. That is, I know there is plenty of reuse going on in Ruby-land. That’s why I’m wondering if it has been an issue.

PJ Hyett said about 21 hours later:

Sorry for not responding Tom. The namespace issue is indeed an issue. The flexibility that Ruby provides allows for naming conflicts, you are correct. That having been said, I don’t think Ruby has a large enough project base with a huge number of users that it has to be addressed right away honestly.

Personally, I have never run into any naming conflicts and from my Ruby readings online, I haven’t heard of any others running into any problems either.

I’m sure there are others that could give you a much better answer than this Ruby-newbie could.

Tom said 1 day later:

Okay. Thanks for the info. Maybe I’ll go to main mailing list (assuming there is one?) and ask some time. I keep meaning to get around to it. I just got reminded from your blog post. So anyway, thanks again for the response.

Chris said 2 days later:

Now I’m not an expert about Ruby namespacing, but I’ve run into namespace clashes before, and from what I can tell, you can get around problems like this to some degree. I was using WWW::Mechanize and Rails together and they both defined a Tag class and extended it (for HTML tags) causing weird errors about inconsistent hierarchies. The fix was to import the WWW::Mechanize code inside the module/class I used it in, rather than up at the top of the file into the global namespace. This avoided the clash. Library authors should keep namespace issue like this in mind and contain their core class extensions inside a namespace, rather than at the global level.

Sorry, comments have been closed for this post.