|Functors and Function Objects|
|Written by Mike James|
|Monday, 15 August 2011|
Page 1 of 2
One of the delights of C++ is how often you can discover a new use for something. In this case it is the ability to redefine operators that can be "repurposed" to create function objects or functors.
First let's take a look at the problem that functors solve.
The code problem
Object oriented programming is currently the best general purpose programming philosophy we have but it has its problems. One of the biggest problems, although rarely expressed clearly, is what to do with the code. Before objects we used pure procedural programming where a big program was broken down into small chunks - called functions, procedures or subroutines depending on your viewpoint. This was generally called top-down or bottom-up modular programming and it was the best we had.
Object-oriented programming takes the modular code and puts it where it belongs with the data that is works with. That is objects have properties, i.e. data, and they have methods that work on that data, i.e. methods. This is great but occasionally it seems natural to think about a function as something on its own - something not connected to an object.
This a big problem for object-oriented languages and you can find opinion split between allowing standalone functions or demanding that every function belongs to an object. A language that allows functions to stand on their own can't really be called 100% object oriented - unless that is you make stand alone functions objects in their own right.
That is you can stick to the "everything is an object" approach and have what look like standalone functions by the simple trick of allowing objects which are functions. In most languages a function object is called either a function object or a first class function but in C++ and a few languages the term functor is also used. The term functor comes from category theory where it is a type of function which maps one category to another homomorphically. Don't worry if you have no idea what all this means - I quote it just to indicate that the use of the term "functor" in connection with function objects is more about intellectual elitism than it is about the accurate use of terminology.
As far as C++ and other language programmers are concerned functor means an object which behaves as a function.
It is also worth knowing that other languages go to a lot of trouble not to introduce function objects with the same status as other objects. For example, in C# delegates are a way of wrapping a function that belongs to another object. This still doesn't allow you to create stand-alone objects but now you can at least pass a function as if it was an object. Eventually C# had to introduced a standalone function and it did so in the form of a lambda expression which is a standalone function defined on the fly. Interestingly C++0x has also added the lambda expression to the language and this provides another way to construct a standalone function but this time on the fly.
To return to the idea of functor in C++ we first need to remember how to create a custom operator. First some basic facts - you can only redefine existing operators which keep their precedence and associativity rules. You redefine an operator within a class and the redefinition applies only to that class. That is if you redefine ++ in MyClass then MyObj++ uses the new definition of the operator if and only if MyObj is of type MyClass. Any other input parameter and return value can be of any type you care to define.
For a simple example let's redefine ++ to mean increment by 2 rather than 1. First we need to define the class and the overload for the operator:
public class MyClass
Notice that the return type is int. It is more usual for the return type to be the same type as the object the operator acts on.
Now that we have the definition of the class we can try it out:
You will discover that result holds 3 as it should.
If you want to redefine a binary operator simply add a parameter in the operator definition e.g.
int operator + (int y)
Notice that you can't change the arity of an operator - if the operator is binary it has to be redefined as a binary operator.
Creating a Functor
Now we can put this to a slightly different use by overloading the function operator (). The () operator evaluates the function to its left and this is an operator that can be redefined. For example, if you want a function that adds one to its parameter and returns the result you can code this as:
public class MyFunctor
To make use of this function object you have to instantiate it and this is about the only real difference you will notice in the use of a function object as opposed to a function that does the same job:
Notice that even though MyFunction looks like a function it really is an object. That is MyFunctor can have properties, methods, constructors and destructors in addition to the function it implements and it can be passed to other functions just like any other object.
|Last Updated ( Monday, 15 August 2011 )|