Tags Ruby

Ruby 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.


Comments

comments powered by Disqus