Zig Function Values
A function value is a function passed into another function as an argument. This lets the receiving function run work that the caller chose.
Pass a function and call it
Apply receives a function through an anytype parameter. It calls that function once on the given number.
const std = @import("std");
fn increment(n: i32) i32 {
return n + 1;
}
fn apply(f: anytype, x: i32) i32 {
return f(x);
}
pub fn main() !void {
const out = std.io.getStdOut().writer();
try out.print("{d}\n", .{apply(increment, 41)});
}Apply the passed function twice
ApplyTwice feeds the result of the first call into a second call. Doubling 3 twice gives 12.
const std = @import("std");
fn double(n: i32) i32 {
return n * 2;
}
fn applyTwice(f: anytype, x: i32) i32 {
return f(f(x));
}
pub fn main() !void {
const out = std.io.getStdOut().writer();
try out.print("{d}\n", .{applyTwice(double, 3)});
}Pass a different function instead
The receiving function stays the same. Passing a different function changes the result.
const std = @import("std");
fn addTen(n: i32) i32 {
return n + 10;
}
fn square(n: i32) i32 {
return n * n;
}
fn apply(f: anytype, x: i32) i32 {
return f(x);
}
pub fn main() !void {
const out = std.io.getStdOut().writer();
try out.print("{d} {d}\n", .{ apply(addTen, 5), apply(square, 5) });
}Example
const std = @import("std");
fn double(n: i32) i32 {
return n * 2;
}
fn addFive(n: i32) i32 {
return n + 5;
}
fn applyTwice(f: anytype, x: i32) i32 {
return f(f(x));
}
pub fn main() !void {
const out = std.io.getStdOut().writer();
try out.print("{d} {d}\n", .{ applyTwice(double, 3), applyTwice(addFive, 3) });
}Key points
- anytype: a parameter marked anytype accepts a value of any type, and Zig works out that type at compile time.
- Pass by name: writing a function's name without parentheses passes the function itself, instead of calling it.
- Call through the parameter: adding parentheses and an argument to the parameter's name runs the passed function.
- Callback: a function passed in so another function can call it is often called a callback.
- Choice at the call: different calls can pass different functions into the same receiving function.
In this example, applyTwice calls whichever function it receives two times in a row. Passing double turns 3 into 6 and then 12. Passing addFive turns 3 into 8 and then 13, and main prints both results.
Note
the passed function must match what the receiving function expects, in this lesson one i32 in and one i32 back.
Try it Yourself
Edit the code, then press Run.
Running is simulated
Exercise
In the call `apply(square, 5)`, why is square written without parentheses?