Function object: Difference between revisions

Content deleted Content added
Bender the Bot (talk | contribs)
m External links: HTTP to HTTPS for SourceForge
 
(24 intermediate revisions by 15 users not shown)
Line 1:
{{Short description|Programming construct}}
{{About|the computer programming concept of function objects|functors in mathematics|Functor|the related concept in functional programming|Functor (functional programming)}}
{{RefimproveMore citations needed|date=February 2009}}
In [[computer programming]], a '''function object'''{{efn|1=In C++, a '''functionoid''' is an object that has one major method, and a '''functor''' is a special case of a functionoid.<ref>[https://isocpp.org/wiki/faq/pointers-to-members#functor-vs-functionoid What's the difference between a functionoid and a functor?]</ref> They are similar to a function object, ''but not the same''.}} is a construct allowing an [[object (computer science)|object]] to be invoked or called as if it were an ordinary [[subroutine|function]], usually with the same syntax (a function parameter that can also be a function). FunctionIn some languages, particularly C++, function objects are often called '''functors''' (not related to [[Functor (functional programming)|the functional programming concept]]).
 
== Description ==
Line 24 ⟶ 25:
 
== In C and C++ ==
Consider the example of a sorting routine that uses a callback function to define an ordering relation between a pair of items. The following C/C++ program uses function pointers:
<!-- NOTE: For the compareInts() implementation below, see http://stackoverflow.com/a/10997428/1629102 for an explanation of why the more simple (int) a - (int) b would not work in all cases. -->
<syntaxhighlight lang="c">
Line 32 ⟶ 33:
int compareInts(const void* a, const void* b)
{
return ( *(int *)a - *(int *)b) );
}
...
Line 78 ⟶ 79:
}
bool operator()(const Employee& a, const Employee& b) const
{
if (SORT_FIELD == "name")
Line 112 ⟶ 113:
/* code to populate database */
const std::string sort_field = "idnum";
std::sort(emps.begin(), emps.end(), [&sort_field](const Employee& a, const Employee& b) const { /* code to select and compare field */ });
return 0;
}
Line 126 ⟶ 127:
 
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 [[generic programming|template]] facilities. The expressiveness of templates allows some [[functional programming]] techniques to be used, such as defining function objects in terms of other function objects (like [[function composition (computer science)|function composition]]). Much of the C++ [[Standard Template Library]] (STL) makes heavy use of template-based function objects.
 
Another way to create a function object in C++ is to define a non-explicit conversion function to a function pointer type, a function [[reference (C++)|reference]] type, or a reference to function pointer type. Assuming the conversion does not discard [[Type qualifier|cv-qualifiers]], this allows an object of that type to be used as a function with the same [[function signature|signature]] as the type it is converted to. Modifying an earlier example to use this we obtain the following class, whose instances can be called like function pointers:<ref>{{cite web|url=https://en.cppreference.com/w/cpp/language/overload_resolution#Call_to_a_class_object|title=Overload resolution§Call to a class object|website=cppreference.com}}</ref>
 
<syntaxhighlight lang="cpp">
// comparator predicate: returns true if a < b, false otherwise
struct IntComparator
{
static bool compare(const int &a, const int &b)
{
return a < b;
}
using T = decltype(compare);
operator T*() const { return compare; }
};
 
int main()
{
std::vector<int> items { 4, 3, 1, 2 };
std::sort(items.begin(), items.end(), IntComparator());
return 0;
}
</syntaxhighlight>
 
=== Maintaining state ===
Line 272 ⟶ 295:
</syntaxhighlight>
 
The routine <code>extend</code> referenced in the example above is a feature of a class in a [[graphical user interface]] (GUI) library to provide [[event-driven programming]] capabilities.
 
In other library classes, agents are seen to be used for different purposes. In a library supporting data structures, for example, a class modeling linear structures effects [[universal quantification]] with a function <code>for_all</code> of type <code>BOOLEAN</code> that accepts an agent, an instance of <code>FUNCTION</code>, as an argument. So, in the following example, <code>my_action</code> is executed only if all members of <code>my_list</code> contain the character '!':
Line 331 ⟶ 354:
<syntaxhighlight lang="java">
List<String> list = Arrays.asList("10", "1", "20", "11", "21", "12");
 
Comparator<String> numStringComparator = new Comparator<String>() {
public int compare(String str1, String str2) {
Line 344 ⟶ 367:
<syntaxhighlight lang="java">
List<String> list = Arrays.asList("10", "1", "20", "11", "21", "12");
 
Comparator<String> numStringComparator = (str1, str2) -> Integer.valueOf(str1).compareTo(Integer.valueOf(str2));
 
Line 377 ⟶ 400:
 
== In Julia ==
In [[Julia_Julia (programming_languageprogramming language)|Julia]], methods are associated with types, so it is possible to make any arbitrary Julia object "callable" by adding methods to its type. (Such "callable" objects are sometimes called "functors.")
 
An example is this accumulator mutable struct (based on [[Paul Graham (computer programmer)|Paul Graham's]] study on programming language syntax and clarity):<ref>[http://www.paulgraham.com/accgen.html Accumulator Generator]</ref>
 
<syntaxhighlight lang="julia-repl">
julia> mutable struct Accumulator
n::Int
Line 408 ⟶ 431:
Such an accumulator can also be implemented using closure:
 
<syntaxhighlight lang="julia-repl">
julia> function Accumulator(n0)
n = n0
Line 440 ⟶ 463:
Many uses of functors in languages like C++ are simply emulations of the missing closure constructor. Since the programmer cannot directly construct a closure, they must define a class that has all of the necessary state variables, and also a member function. Then, construct an instance of that class instead, ensuring that all the member variables are initialized through its constructor. The values are derived precisely from those local variables that ought to be captured directly by a closure.
 
A function-object using the class system in Common Lisp, no use of closures:
 
<syntaxhighlight lang="lisp">
Line 458 ⟶ 481:
</syntaxhighlight>
 
Since there is no standard way to make funcallable objects in Common Lisp, we fake it by defining a [[generic function]] called FUNCTOR-CALL. This can be specialized for any class whatsoever. The standard FUNCALL function is not generic; it only takes function objects.
 
It is this FUNCTOR-CALL generic function that gives us function objects, which are ''a computer programming construct allowing an object to be invoked or called as if it were an ordinary function, usually with the same syntax.'' We have ''almost'' the same syntax: FUNCTOR-CALL instead of FUNCALL. Some Lisps provide ''funcallable'' objects as a simple extension. Making objects callable using the same syntax as functions is a fairly trivial business. Making a function call operator work with different kinds of ''function things'', whether they be class objects or closures is no more complicated than making a + operator that works with different kinds of numbers, such as integers, reals or complex numbers.
Line 474 ⟶ 497:
</syntaxhighlight>
 
Scheme makes closures even simpler, and Scheme code tends to use such [[higher-order programming]] somewhat more idiomatically.
 
<syntaxhighlight lang="scheme">
Line 505 ⟶ 528:
</syntaxhighlight>
 
An advantage of <code>NSInvocation</code> is that the target object can be modified after creation. A single <code>NSInvocation</code> can be created and then called for each of any number of targets, for instance from an observable object. An <code>NSInvocation</code> can be created from only a protocol, but it is not straightforward. See {{usurped|1=[https://web.archive.org/web/20110227215311/http://www.a-coding.com/2010/10/making-nsinvocations.html here]}}.
 
== In Perl ==
Line 566 ⟶ 589:
== In PHP ==
 
[[PHP]] 5.3+ has [[first-class function]]s that can be used e.g. as parameter to the {{Code|usort()}} function:
 
<syntaxhighlight lang="php">
Line 573 ⟶ 596:
</syntaxhighlight>
 
[[PHP]] 5.3+, supports also lambda functions and closures.
 
<syntaxhighlight lang="php">
Line 596 ⟶ 619:
</syntaxhighlight>
 
It is also possible in PHP 5.3+ to make objects invokable by adding a magic {{Code|__invoke()}} method to their class:<ref name="phpinvoke">[http://php.net/manual/en/language.oop5.magic.php#object.invoke PHP Documentation on Magic Methods]</ref>
 
<syntaxhighlight lang="php">
Line 662 ⟶ 685:
</syntaxhighlight>
 
Since functions are objects, they can also be defined locally, given attributes, and returned by other functions, <ref>[https://docs.python.org/3/reference/compound_stmts.html#function-definitions Python reference manual - Function definitions]</ref> as demonstrated in the following example:
 
<syntaxhighlight lang="python3">
Line 684 ⟶ 707:
</syntaxhighlight>
 
Now, method <code>foo</code> can be a function object, i.e. a <code>Proc</code>, via <code>&:foo</code> and used via <code>takes_a_functor(&:foo)</code>. <code>Symbol.to_proc</code> was officially added to Ruby on June 11, 2006, during RubyKaigi2006. [https://web.archive.org/web/20060820025032/http://redhanded.hobix.com/cult/symbolTo_procExonerated.html]
 
Because of the variety of forms, the term Functor is not generally used in Ruby to mean a Function object.
Line 708 ⟶ 731:
The [[ML (programming language)|ML]] family of [[functional programming]] languages uses the term ''functor'' to represent a [[function (mathematics)|mapping]] from modules to modules, or from types to types and is a technique for reusing code. Functors used in this manner are analogous to the original mathematical meaning of [[functor]] in [[category theory]], or to the use of generic programming in C++, Java or [[Ada (programming language)|Ada]].
 
In [[Haskell (programming language)|Haskell]], the term ''[[Functor (functional programming)|functor]]'' is also used infor a concept related to the samemeaning senseof as''functor'' in category theory.
 
In [[Prolog]] and related languages, ''functor'' is a synonym for [[function symbol]].
Line 731 ⟶ 754:
== External links ==
* [http://c2.com/cgi/wiki?FunctorObject Description from the Portland Pattern Repository]
* [http://www.two-sdg.demon.co.uk/curbralan/papers/AsynchronousC++.pdf C++ Advanced Design Issues - Asynchronous C++] {{Webarchive|url=https://web.archive.org/web/20200922012516/http://www.two-sdg.demon.co.uk/curbralan/papers/AsynchronousC++.pdf |date=2020-09-22 }} by [[Kevlin Henney]]
* [http://www.newty.de/fpt/index.html The Function Pointer Tutorials] by Lars Haendel (2000/2001)
* Article "[https://web.archive.org/web/20041009232434/http://www.cuj.com/documents/s%3D8464/cujcexp0308sutter/ Generalized Function Pointers]" by [[Herb Sutter]]
* [httphttps://jga.sourceforge.net/ Generic Algorithms for Java]
* [https://web.archive.org/web/20100330073950/http://www.amcgowan.ca/blog/computer-science/php-functors-function-objects-in-php/ PHP Functors - Function Objects in PHP]
* [https://web.archive.org/web/20041013202445/http://www.parashift.com/c++-faq-lite/pointers-to-members.html#faq-33.10 What the heck is a functionoid, and why would I use one?] (C++ FAQ)
Line 743 ⟶ 766:
[[Category:Articles with example C code]]
[[Category:Articles with example C++ code]]
[[Category:Articles with example D code]]
[[Category:Articles with example Eiffel code]]
[[Category:Articles with example Java code]]
[[Category:Articles with example JavaScript code]]
[[Category:Articles with example Julia code]]
[[Category:Articles with example Lisp (programming language) code]]
[[Category:Articles with example Objective-C code]]
[[Category:Articles with example Perl code]]
[[Category:Articles with example PHP code]]
[[Category:Articles with example Python (programming language) code]]
[[Category:Articles with example Ruby code]]