Language comparisons are usually flawed

There are many blog posts that basically say, "Given problem X, you can solve it elegantly in language Y. Language Y is awesome!" The problem with this is that it is essentially a strawman argument. Who is to say that problem X would even be the same in other languages, if you take their conventions and idioms into account?

An example is a post "Python is still awesome" where problem X is "Given a list of dictionaries, sum the values of one of the dictionary keys."

d = [{'value':1, 'title':'one'}, {'value':2}, {'value':3},
         {'value':4, 'title':'four'}, ]

The solution is:

s = sum([i['value'] for i in d])

Now, before I continue, let me say that the solution is very elegant. I like Python, and list comprehensions are indeed awesome. They are one of my favorite things about Python. (Nested ones get a little hard to grok, but I digress...)

So I thought about how I would solve that particular Problem X in RoR:

d = [{:value => 1, :title => "one"}, {:value => 2}, {:value => 3},
                {:value => 4, :title => "four"}]
 
s = d.collect{|item| item[:value]}.sum

Pretty good, but only because the sum method is added to Enumerable in ActiveSupport. Outside of Rails you'd have to use inject, and it would not be as nice. (Hopefully others think so too, and sum makes it into Ruby 2.0.) Overall I like the list-comprehension solution a bit better.

However—and this is the crux of the issue—in Ruby, Problem X generally does not occur. Why? Ruby makes it so easy to make objects for the items that I rarely need data structures like that. I can create a simple Item class:

class Item
  attr_accessor :title, :value
end

Now I have Item objects, complete with accessors (item.title, item.value, etc). This is much more elegant than data structures, particularly if there will be a lot of manipulation of the data. So instead of Problem X, the problem boils down to summing the values of a list of Item objects instead of anonymous hashes. And that would look like this:

s = d.collect(&:value).sum

In broad strokes, it's very easy to see what's happening there: you're collecting values from d and summing them. This uses the nifty Symbol#to_proc feature in Ruby 1.9+ that allows you to convert the symbol :value to a Proc object, which essentially makes it shorthand for:

s = d.collect{|x| x.value}.sum

It's got a bit of a magicky feel, especially for those who are not well-versed in Ruby. Fortunately, Sam Huri provides a clever solution, Enumerable#pluck, which adds the pluck method to all things enumerable. The pluck method is basically a short one-liner. With it, the solution to the problem becomes:

s = d.pluck(:value).sum

One character different, but much more understandable. I hope pluck makes it into Ruby 2.0, too.

After this long example, what I have is essentially a solution to a different problem. But it is necessarily so, because languages tend to be used differently. In Perl or PHP, I would use an array-of-hashes because creating objects with accessors is not as simple, nor is it convention.

2 comments ↓

#1 Mark Wilden on 02.16.08 at 2:06 pm

Good stuff!

Note that

s = d.collect(&:value).sum

is valid in Ruby 1.8.6.

///ark

#2 Mark Thomas on 02.17.08 at 10:40 pm

Mark,

That only works inside Rails. Otherwise you need Ruby 1.9.

Leave a Comment