Jean-Pierre follows up with a common gui situation - a combobox dropdown that lists some available functions. When the user clicks an entry, the code is given an enum value.
How can you use an enum to select which function to run?
This can trip up people especially if they are used to languages like Javascript or Racket where functions are first-class constructs. You can put all the functions in a list, index into the list and call the function.
Can we do that in Zig? Yes, as long as all the functions have the same type:
const std = @import("std");
var count: i32 = 0;
pub fn printFn() void {
std.debug.print("count is {d}\n", .{count});
}
pub fn incrementFn() void {
count += 1;
}
pub const FnEnum = enum {
print,
increment,
pub const Table = [@typeInfo(FnEnum).Enum.fields.len]*const fn () void{
printFn,
incrementFn,
};
};
pub fn main() !void {
var input: FnEnum = .print; // User clicks "print"
FnEnum.Table[@enumToInt(input)]();
input = .increment; // User clicks "increment"
FnEnum.Table[@enumToInt(input)]();
input = .print; // User clicks "print" again
FnEnum.Table[@enumToInt(input)]();
}
What if the functions have different types?
I would manually switch on the enum for each function:
const std = @import("std");
var count: i32 = 0;
pub fn printFn() void {
std.debug.print("count is {d}\n", .{count});
}
pub fn incrementFn(v: *i32) void {
v.* += 1;
}
pub const FnEnum = enum {
print,
increment,
pub fn run(self: FnEnum) void {
switch (self) {
.print => printFn(),
.increment => _ = incrementFn(&count),
}
}
};
pub fn main() !void {
var input: FnEnum = .print; // User clicks "print"
input.run();
input = .increment; // User clicks "increment"
input.run();
input = .print; // User clicks "print" again
input.run();
}
Hope this helps!
Oldest comments (3)
Thanks a lot
thank you, the second solution is that
Very interesting to make software whose function call is encapsulated in fields for example, we click on the country, and we must display the function which offers to choose the country
You should be able to put the functions in a struct and index into
@typeInfo(impl).Struct.decls[i]
. Also you could use a comptime [enum tag <-> function pointer] map, or compare@tagName
againstdecls[i].name
.Although I personally can't think of any case right now where I'd not just use an enum plus a switch. It's a lot more straight-forward.
Maybe we'll have anonymous functions functions in the future. Perhaps then using a union(enum) of functions could be interesting, if only to avoid having to keep the enum, the action implementation and the matching code in sync.