I’ve been a C++ developer ever since I discovered the language in the early 90’s and I realized that my beloved Pascal had nothing on objects. I’ve spent plenty of time working with other languages, of course, and over the past year or so I’ve written almost exclusively Ruby. But, one thing I’ve missed about C++ is the ease with which you can make objects act like functions.
In case your C++ is a little rusty, here’s an example:
class Fibonacci {
public:
Fibonacci(): n1_(1), n2_(1) {}
int operator()() {
int result = n1_;
n1_ = n2_;
n2_ = result + n2_;
return result;
}
private:
int n1_, n2_;
};
What you’re looking at there is an overload of the function call operator. No, I’m not kidding; that will compile and run. Instances of the Fibonacci class are called function objects, or functors.
Now, you’re wondering to yourself why anyone would care. The answer is, this function can now carry state around with it:
Fibonacci fibonacci;
fibonacci(); // 1
fibonacci(); // 1
fibonacci(); // 2
Fibonacci()(); // 1
vector<int> v(5);
generate(v.begin(), v.end(), Fibonnaci()); // [1, 1, 2, 3, 5]
generate(v.begin(), v.end(), fibonnaci); // [3, 5, 8, 13, 21]
This may not seem particularly compelling for generating Fibonnaci numbers, but consider generators that may carry more complex state, or references to state owned by other objects. Consumers can also set initial state, such as a seed value for a random number generator, via the ctor.
Also, consider the generate
method above. It expects a third parameter that supports function call semantics with arity of zero. And nothing else. That parameter could be a function pointer (should you desire statelessness and impenetrable syntax), a functor of any type, or anything else that supports operator (). That’s duck-typing, my friends. In a statically-typed language. Dogs and cats sleeping together, and all that.
Again, you cry, why would anyone care? Well, blocks in Ruby carry around the state of the context in which they were created, but sometimes you want more. For instance, if you pass your Proc object around your code may be clearer with the state explicitly encapsulated. The initial state may simply not make sense as local variables when you create the Proc. You may want to save some secondary value that a consumer can query the functor for (how many Fibonacci numbers has this generator generated). Or, perhaps you want consumers to be able to mutate the state in some way.
In any case, this functor approach wacked me over the head recently while I was looking at some code that used the Rails Symbol#to_proc. We all know that Rails adds voodoo to symbols so that
User.find(:all).collect(&:name)
is equivalent to
User.find(:all).collect { |u| u.name }
And, we all know that this works because the & operator, when applied to an object in a parameter list, will implicitly call #to_proc on that object and then convert the result to a block. This is vanilla Ruby functionality, Rails just adds #to_proc to the Symbol class.
So, duh. Check it out:
class Fibonacci
def initialize
@n1 = @n2 = 1
end
def to_proc
@proc ||= Proc.new do
result = @n1
@n1, @n2 = @n2, @n1 + @n2
result
end
end
end
fibonacci = Fibonacci.new
fibonacci.call # 1
fibonacci.call # 1
fibonacci.call # 2
Fibonacci.new.call # 1
(1..5).collect(&Fibonacci.new) # [1, 1, 2, 3, 5]
(1..5).collect(&fibonacci) # [3, 5, 8, 13, 21]
Voilà, a functor. I’d love to hear from anyone who has used this technique to do something really cool.
About the Author