A function can also be a parameter to another function:
void doSomething(int function(int, int) doer) {
// call passed function
doer(5,5);
}
doSomething(add); // use global function `add` here
// add must have 2 int parameters
doer
can then be called like any other normal function.
The above example uses the function
type which is
a pointer to a global function. As soon as a member
function or a local function is referenced, delegate
's
have to be used. It's a function pointer
that additionally contains information about its
context - or enclosure, thus also called closure
in other languages. For example a delegate
that points to a member function of a class also includes
the pointer to the class object. A delegate
created by
a nested function includes a link to the enclosing context
instead. However, the D compiler may automatically make a copy of
the context on the heap if it is necessary for memory safety -
then a delegate will link to this heap area.
void foo() {
void local() {
writeln("local");
}
auto f = &local; // f is of type delegate()
}
The same function doSomething
taking a delegate
would look like this:
void doSomething(int delegate(int,int) doer);
delegate
and function
objects cannot be mixed. But the
standard function
std.functional.toDelegate
converts a function
to a delegate
.
As functions can be saved as variables and passed to other functions, it is laborious to give them their own name and to define them. Hence D allows nameless functions and one-line lambdas.
auto f = (int lhs, int rhs) {
return lhs + rhs;
};
auto f = (int lhs, int rhs) => lhs + rhs; // Lambda - internally converted to the above
It is also possible to pass-in strings as template arguments to functional parts of D's standard library. For example they offer a convenient way to define a folding (aka reducer):
[1, 2, 3].reduce!`a + b`; // 6
String functions are only possible for one or two arguments and then use a
as first and b
as second argument.