Ruby as both a functional and an OO language
March 25th, 2006 at 6:51 amRuby is a functional language – which means that its functions are first-class objects – functions can be created in runtime, stored in data structures, passed as arguments to other functions and so on. Consider the following example:
debts = [['Alex', 250], ['Mary', 244], ['George', 501]]
debts_after_tax = debts.map {|o| o[1] *= 1.2; o}
The block that follows map is a new function, constructed and evaluated at runtime – passed in as an argument to map. This is an ‘anonymous function’ – it has no name and is created only once to do some job.
Say we want to turn an array of strings into integers. Here’s an example:
str = "1-800-50-50-68"
ar = str.split(/-/).map {|o| o.to_i}
Note that, once again, we use map to iterate over all values in an array (that is returned by split) and apply a function to each value. Here, however, we see an actual deficiency in standard Ruby. We simply call one function on each object, why should it go through another new, anonymous function ? In fact, this is easily fixable, and the fix displays Ruby’s Object Oriented nature.
In Ruby everything is an object, including of course arrays. Arrays are derived from Enumerable, which actually defines the map method (and its synonim collect). We can add another form of map right into Enumerable:
module Enumerable
def mapf(method, *args)
map {|obj| obj.send(method, *args)}
end
end
Now we can simplify the last example to:
str = "1-800-50-50-68" ar = str.split(/-/).mapf(:to_i)
mapf is a new mapping method that takes a function name as an argument (represented by a Symbol in Ruby – symbols are generally used to represent names of things), and applies this function to all the values it iterates on.
Note how natural the new call looks. In some functional but non-OO languages, we would have probably done something like:
ar = mapf(:to_i, split(/-/, str))
But since Ruby is fully object oriented, its way is simpler and much easier to understand.
Related posts:

March 25th, 2006 at 12:04
Note that you can go even further with using #to_proc on a Symbol:
class Symbol
def to_proc
lambda {|x| x.send self}
end
end
['1', '2', '3'].map(&:to_i)
Now you can use this with map and other functions:
# -@ is unary -
[1,2,3].sort_by(&:-@)
# Another way to #compact
[true, nil, false, 'hello', nil].reject(&:nil?)
Of course, you can always just pass a block or use Proc objects.
March 25th, 2006 at 15:50
Thank you, this is indeed interestong. I really hope in some future version of Ruby this will be possible without special conversion functions.
March 25th, 2006 at 17:52
Thanks for the article. This line, in particular, is interesting:
But since Ruby is fully object oriented, it’s way is simpler and much easier to understand [than non-OO functional languages].
Don’t you think you are overstating the case a bit? Your supporting example suggests that it all comes down to the notation x.f(args) being obviously simpler than f(x,args), but they seem pretty much equivalent.
Also, in most modern FP languages, programmers don’t write code like the following to nest function calls:
f(w, g(x, y, h(z, o)))
Instead, they use function composition and partial application to create clean-looking pipelines:
(f w . g x y . h z) o
Cheers,
Tom
March 26th, 2006 at 08:54
The notion of ‘clean looking’ is a matter of personal taste, and I certainly find the object method cleaner here, mostly because it’s obvious that the mapping is applied to an array object.
September 7th, 2006 at 09:47
Arrays are derived from Enumerable
Arrays don’t derive from it – not according to usual OO parlance anyway. Enumerable is actually mixed in. That was probably what you meant. Just thought I’d point it out. Could confuse readers.