| Function Object |
Article Index for Function |
Website Links For Function |
Information AboutFunction Object |
| CATEGORIES ABOUT FUNCTION OBJECT | |
| programming constructs | |
|
DESCRIPTION A typical use of a functor is in writing more intelligent Callback Functions . A callback in Procedural Languages , such as C , may be accomplished by using Function Pointers . However it can be difficult or awkward to pass state into or out of the callback function. This restriction also inhibits more dynamic behavior of the function. A functor solves those problems since the function is really a Façade for a full object, thus it carries its own state. Most modern object-oriented languages such as C++ , Java , Python , and Ruby support the definition of functors and may even make significant use of them. ORIGINS Smalltalk was one of the first languages to support functors through the use of block constructs that are an integral part of the language syntax. For example, one can supply functors as arguments to collection objects to provide filtering & sorting. It is a perfect realization of the Strategy Pattern that promotes the use of pluggable behaviour. FUNCTORS IN C AND C++ Consider the example of a sorting routine which uses a callback function to define an ordering relation between a pair of items. A C program using function pointers may appear as:
int compare_function(int A, int B) { return (A < B); } ...
... int main() { int items {Link without Title} = {4, 3, 1, 2}; sort_ints(items, 4, compare_function); } In C++ a functor may be used instead of an ordinary function by defining a class which Overloads the Function Call Operator by defining an operator() member function. In C++ this is called a '''class type functor''', and may appear as follows: class compare_class { public: bool operator()(int A, int B) { return (A < B); } }; ... // Declaration of C++ sorting function. template
... int main() { int items {Link without Title} = {4, 3, 1, 2}; compare_class functor; sort_ints(items, 4, functor); } Notice that the syntax for providing the callback to the sort_ints() function is identical, but an object is passed instead of a function pointer. When invoked the callback function is executed just as any other member function, and therefore has full access to the other members (data or functions) of the object. It is possible to use function objects in situations other than as callback functions (although the shortened term ''functor'' is normally not used). Continuing the example, functor_class Y; int result = Y( a, b ); In addition to class type functors, other kinds of function objects are also possible in C++. They can take advantage of C++'s member-pointer or Template facilities. The expressiveness of templates allows some Functional Programming techniques to be used, such as defining functors in terms of other functors (like Function Composition ). Much of the C++ Standard Template Library (STL) makes heavy use of template-based function objects. Performance An advantage of function objects in C++ is performance because unlike a function pointer, a function object can be inlined. For example, consider a simple function which increments its argument implemented as a function object: struct IncrementFunctor { void operator()(int&i) { ++i; } }; and as a free function: void increment_function(int&i) { ++i; } Recall the standard library function std::for_each():template Function for_each(InputIterator first, InputIterator last, Function f) { for ( ; first != last; ++first)
return f; } Suppose we apply std::for_each() like so:int A {Link without Title} = {1, 4, 2, 8, 5, 7}; const int N = sizeof(A) / sizeof(int); for_each(A, A + N, IncrementFunctor()); for_each(A, A + N, increment_function); Both calls to for_each() will work as expected. The first call will be to this version:
the second will be to this version:
Actually, a function can easily be known at compile time and the compiler will happily inline it, if it is instructed to. The only requirement is that the compiler has seen the function definition, and that applies equally to functions inside a class or outside. In case we are not inlining however, the linker is instructed to "silently" drop multiple definitions of the same function from different compilation units, without producing an error, but only if said function is a class function. The linker will not dismiss multiple definition of the same function if it is not a class function. Maintain State One advantage of functors is that they can maintain state (as fields of the object) between calls. For example, the following code defines a Generator (a function that takes no arguments) that counts from 10 up, and we invoke the generator 11 times and print the results.
FUNCTORS IN JAVA Functors in Java are typically expressed by defining a Method Signature in a Base Class (or an Interface ). Then different functors are created by deriving from the interface. This could be called an inheritance model of functors. Take Apache's and Transformation functors. EqualPredicate, for instance, could be used as follows.
Notice that p is an object having evaluate method, so it can be treated like every other object.FUNCTORS IN PYTHON In Python, functions are objects, just like strings, numbers, lists, and so on. This feature eliminates the need to create a functor object in many cases. However, any object with a __call__() method may be called using function-call syntax.An example is this Accumulator class (based on Paul Graham 's study on programming language syntax and clarity here ): An example of this in use (using the interactive interpreter): Due to the dynamic nature of the language an ordinary object can be converted into a functor at run-time, but this is rare in practice. FUNCTORS IN LISP In Common Lisp, and languages in that family, functions are objects, just like strings, vectors, lists, numbers and so forth. A closure-constructing operator creates a function-object from a piece of the program itself: the piece of code given as an argument to the operator is part of the function, and so is the lexical environment: the bindings of the lexically visible variables are "captured" and stored in the functor, which is more commonly called a Closure . The captured bindings play the role of "member variables", and the code part of the closure plays the role of the "anonymous member function", just like operator () in C++. The closure constructor has the syntax (lambda (parameters ...) code ...). The (parameters ...) |
|
|