Function object: Difference between revisions

Content deleted Content added
No edit summary
Line 29:
Consider the example of a sorting routine that uses a callback function to define an ordering relation between a pair of items. A C program using function pointers may appear as:
<!-- 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"c">
#include <stdlib.h>
 
Line 51:
In C++, a function object may be used instead of an ordinary function by defining a class that [[operator overloading|overloads]] the [[function call operator]] by defining an <code>operator()</code> member function. In C++, this may appear as follows:
 
<syntaxhighlight lang=Cpp"cpp">
// comparator predicate: returns true if a < b, false otherwise
struct IntComparator
Line 71:
Notice that the syntax for providing the callback to the <code>std::sort()</code> 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. Of course, this is just a trivial example. To understand what power a functor provides more than a regular function, consider the common use case of sorting objects by a particular field. In the following example, a functor is used to sort a simple employee database by each employee's ID number.
 
<syntaxhighlight lang=Cpp"cpp">
 
struct CompareBy
{
Line 106 ⟶ 105:
return 0;
}
 
</syntaxhighlight>
 
In [[C++11]], the lambda expression provides a more succinct way to do the same thing.
 
<syntaxhighlight lang=Cpp"cpp">
 
int main()
{
Line 121 ⟶ 118:
return 0;
}
 
</syntaxhighlight>
 
Line 127 ⟶ 123:
It is possible to use function objects in situations other than as callback functions. In this case, the shortened term ''functor'' is normally ''not'' used about the function object. Continuing the example,
 
<syntaxhighlight lang=Cpp"cpp">
IntComparator cpm;
bool result = cpm(a, b);
</syntaxhighlight>
 
Line 137 ⟶ 133:
Another advantage of function objects is their ability to maintain a state that affects <code>operator()</code> between calls. For example, the following code defines a [[generator (computer science)|generator]] counting from 10 upwards and is invoked 11 times.
 
<syntaxhighlight lang=Cpp"cpp">
#include <algorithm>
#include <iostream>
Line 162 ⟶ 158:
In [[C Sharp (programming language)|C#]], function objects are declared via [[delegate (CLI)|delegate]]s. A delegate can be declared using a named method or a [[Lambda (programming)|lambda expression]]. Here is an example using a named method.
 
<syntaxhighlight lang=CSharp"csharp">
using System;
using System.Collections.Generic;
 
public class ComparisonClass1
{
public static int CompareFunction(int x, int y) {
);{
return x - y;
}
 
public static void Main() {
); {
List<int>var items = new List<int> { 4, 3, 1, 2 };
 
Comparison<int> del = CompareFunction;
 
items.Sort(del);
}
Line 183 ⟶ 180:
Here is an example using a lambda expression.
 
<syntaxhighlight lang=CSharp"csharp">
using System;
using System.Collections.Generic;
 
public class ComparisonClass2
{
public static void Main() {
); {
List<int>var items = new List<int> { 4, 3, 1, 2 };
items.Sort((x, y) => x - y);
}
Line 198 ⟶ 197:
[[D (programming language)|D]] provides several ways to declare function objects: Lisp/Python-style via [[closure (computer science)|closures]] or C#-style via [[delegate (CLI)|delegate]]s, respectively:
 
<syntaxhighlight lang=D"d">
bool find(T)(T[] haystack, bool delegate(T) needle_test) {
foreach (straw; haystack) {
Line 213 ⟶ 212:
return n == needle;
}
assert(find(haystack, &needleTest));
find(haystack, &needleTest)
);
}
</syntaxhighlight>
Line 221 ⟶ 218:
The difference between a [[delegate (CLI)|delegate]] and a [[closure (computer science)|closure]] in D is automatically and conservatively determined by the compiler. D also supports function literals, that allow a lambda-style definition:
 
<syntaxhighlight lang=D"d">
void main() {
int[] haystack = [345, 15, 457, 9, 56, 123, 456];
int needle = 123;
assert(find(haystack, (int n) { return n == needle; }));
assert(
find(haystack, (int n) { return n == needle; })
);
}
</syntaxhighlight>
Line 233 ⟶ 228:
To allow the compiler to inline the code (see above), function objects can also be specified C++-style via [[operator overloading]]:
 
<syntaxhighlight lang=D"d">
bool find(T, F)(T[] haystack, F needle_test) {
foreach (straw; haystack) {
Line 252 ⟶ 247:
}
}
assert(find(haystack, new NeedleTest(needle)));
find(haystack, new NeedleTest(needle))
);
}
</syntaxhighlight>
Line 264 ⟶ 257:
Within software text, the language keyword <code>agent</code> allows agents to be constructed in a compact form. In the following example, the goal is to add the action of stepping the gauge forward to the list of actions to be executed in the event that a button is clicked.
 
<syntaxhighlight lang=Eiffel"eiffel">
my_button.select_actions.extend (agent my_gauge.step_forward)
</syntaxhighlight>
 
Line 272 ⟶ 265:
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 '!':
 
<syntaxhighlight lang=Eiffel"eiffel">
my_list: LINKED_LIST [STRING]
...
Line 287 ⟶ 280:
The ability to close or leave open targets and arguments is intended to improve the flexibility of the agent mechanism. Consider a class that contains the following procedure to print a string on standard output after a new line:
 
<syntaxhighlight lang=Eiffel"eiffel">
print_on_new_line (s: STRING)
-- Print `s' preceded by a new line
Line 297 ⟶ 290:
The following snippet, assumed to be in the same class, uses <code>print_on_new_line</code> to demonstrate the mixing of open arguments and open targets in agents used as arguments to the same routine.
 
<syntaxhighlight lang=Eiffel"eiffel">
my_list: LINKED_LIST [STRING]
...
Line 314 ⟶ 307:
Open and closed arguments and targets also allow the use of routines that call for more arguments than are required by closing all but the necessary number of arguments:
 
<syntaxhighlight lang=Eiffel"eiffel">
my_list.do_all (agent my_multi_arg_procedure (closed_arg_1, ?, closed_arg_2, closed_arg_3)
</syntaxhighlight>
 
Line 325 ⟶ 318:
For an example from Java's standard library, <code>java.util.Collections.sort()</code> takes a <code>List</code> and a functor whose role is to compare objects in the List. Without first-class functions, the function is part of the Comparator interface. This could be used as follows.
 
<syntaxhighlight lang=Java"java">
List<String> list = Arrays.asList("10", "1", "20", "11", "21", "12");
Line 338 ⟶ 331:
 
In Java 8+, this can be written as:
<syntaxhighlight lang=Java"java">
List<String> list = Arrays.asList("10", "1", "20", "11", "21", "12");
Line 351 ⟶ 344:
Compare the following with the subsequent Python example.
 
<syntaxhighlight lang=JavaScript"javascript">
function Accumulator(start) {
var current = start;
Line 362 ⟶ 355:
An example of this in use:
 
<syntaxhighlight lang=JavaScript"javascript">
var a = Accumulator(4);
var x = a(5); // x has value 9
Line 377 ⟶ 370:
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"julia">
julia> mutable struct Accumulator
n::Int
Line 404 ⟶ 397:
Such an accumulator can also be implemented using closure:
 
<syntaxhighlight lang=Julia"julia">
julia> function Accumulator(n0)
n = n0
Line 438 ⟶ 431:
A function-object using the class system, no use of closures:
 
<syntaxhighlight lang=Lisp"lisp">
(defclass counter ()
((value :initarg :value :accessor value-of)))
Line 460 ⟶ 453:
Now, a counter implemented using a closure. This is much more brief and direct. The INITIAL-VALUE argument of the MAKE-COUNTER [[factory function]] is captured and used directly. It does not have to be copied into some auxiliary class object through a constructor. It ''is'' the counter. An auxiliary object is created, but that happens ''behind the scenes''.
 
<syntaxhighlight lang=Lisp"lisp">
(defun make-counter (value)
(lambda () (incf value)))
Line 472 ⟶ 465:
Scheme makes closures even simpler, and Scheme code tends to use such higher-order programming somewhat more idiomatically.
 
<syntaxhighlight lang="scheme">
(define (make-counter value)
(lambda () (set! value (+ value 1)) value))
Line 489 ⟶ 482:
In [[Objective-C]], a function object can be created from the <code>NSInvocation</code> class. Construction of a function object requires a method signature, the target object, and the target selector. Here is an example for creating an invocation to the current object's <code>myMethod</code>:
 
<syntaxhighlight lang=ObjC"objc">
// Construct a function object
SEL sel = @selector(myMethod);
Line 507 ⟶ 500:
In [[Perl]], a function object can be created either from a class's constructor returning a function closed over the object's instance data, blessed into the class:
 
<syntaxhighlight lang=Perl"perl">
package Acc1;
sub new {
Line 521 ⟶ 514:
</syntaxhighlight>
 
or by overloading the <code>&{}</code> operator so that the object can be used as a function:
 
<syntaxhighlight lang=Perl"perl">
package Acc2;
use overload
Line 546 ⟶ 539:
In both cases the function object can be used either using the dereferencing arrow syntax ''$ref->(@arguments)'':
 
<syntaxhighlight lang=Perl"perl">
use Acc1;
my $a = Acc1->new(42);
Line 553 ⟶ 546:
</syntaxhighlight>
or using the coderef dereferencing syntax ''&$ref(@arguments)'':
<syntaxhighlight lang=Perl"perl">
use Acc2;
my $a = Acc2->new(12);
Line 564 ⟶ 557:
[[PHP]] 5.3+ has [[first-class function]]s that can be used e.g. as parameter to the usort() function:
 
<syntaxhighlight lang=PHP"php">
$a = array(3, 1, 4);
usort($a, function ($x, $y) { return $x - $y; });
Line 611 ⟶ 604:
In the [[Windows PowerShell]] language, a script block is a collection of statements or expressions that can be used as a single unit. A script block can accept arguments and return values. A script block is an instance of a Microsoft [[.NET Framework]] type System.Management.Automation.ScriptBlock.
 
<syntaxhighlight lang=PowerShell"powershell">
Function Get-Accumulator($x) {
{
Line 672 ⟶ 665:
In [[Ruby (programming language)|Ruby]], several objects can be considered function objects, in particular Method and Proc objects. Ruby also has two kinds of objects that can be thought of as semi-function objects: UnboundMethod and block. UnboundMethods must first be bound to an object (thus becoming a Method) before they can be used as a function object. Blocks can be called like function objects, but to be used in any other capacity as an object (e.g. passed as an argument) they must first be converted to a Proc. More recently, symbols (accessed via the literal unary indicator <code>:</code>) can also be converted to <code>Proc</code>s. Using Ruby's unary <code>&</code> operator&mdash;equivalent to calling <code>to_proc</code> on an object, and [[duck typing|assuming that method exists]]&mdash;the [[Ruby Extensions Project]] [https://web.archive.org/web/20060425104650/http://blogs.pragprog.com/cgi-bin/pragdave.cgi/Tech/Ruby/ToProc.rdoc created a simple hack.]
 
<syntaxhighlight lang=Ruby"ruby">
class Symbol
def to_proc
Line 685 ⟶ 678:
Just a type of dispatch [[delegation (programming)|delegation]] introduced by the [https://web.archive.org/web/20070107205748/http://facets.rubyforge.org/ Ruby Facets] project is named as Functor. The most basic definition of which is:
 
<syntaxhighlight lang=Ruby"ruby">
class Functor
def initialize(&func)
Line 740 ⟶ 733:
[[Category:Articles with example C++ code]]
[[Category:Articles with example Java code]]
[[Category:Articles with example Julia code]]
[[Category:Articles with example Perl code]]
[[Category:Articles with example Python (programming language) code]]
[[Category:Articles with example Ruby code]]
[[Category:Articles with example Julia code]]