Generic Functions
Another use of comptime is generic functions, also known as polymorphic functions.
As an example, let’s define a clamp function that limits its values to be within a certain range:
const std = @import("std");
const print = std.debug.print;
fn clamp(comptime T: type, val: T, min: T, max: T) T {
if (val < min) return min;
if (val > max) return max;
return val;
}
pub fn main() void {
print("{}\n", .{clamp(f64, 1.2, 0.0, 1.0)});
print("{}\n", .{clamp(u64, 120, 0, 100)});
}$ zig run generic.zig
1
100
What if we want clamp to work for arrays as well?
const std = @import("std");
const print = std.debug.print;
// Let’s start with a function just for arrays.
fn clampArray(T: type, val: T, min: T, max: T) T {
// E is the type of the array elements.
const E = @TypeOf(val[0]);
var result: T = undefined;
for (&result, 0..) |*p, i|
p.* = clamp(E, val[i], min[i], max[i]);
return result;
}
fn clamp(T: type, val: T, min: T, max: T) T {
// Special case if T is an array type:
if (@typeInfo(T) == .array)
return clampArray(T, val, min, max);
if (val < min) return min;
if (val > max) return max;
return val;
}
pub fn main() void {
print("{}\n", .{clamp(f64, 1.2, 0.0, 1.0)});
print("{}\n", .{clamp(u64, 120, 0, 100)});
var a: [3]f64 = .{ -0.1, 0.4, 1.2 };
a = clamp([3]f64, a, @splat(0.0), @splat(1.0));
print("{} {} {}\n", .{ a[0], a[1], a[2] });
}$ zig run generic-2.zig
1
100
0 0.4 1
Next example: Generic Types.