Zig Comptime Branches
A comptime branch is a branch whose condition is known during compilation, so only the chosen side is kept. It lets code adapt to the shape of a type without checking anything at run time.
Present or absent
One type stores a label declaration and another does not, so @hasDecl reports true for the first and false for the second.
const std = @import("std");
pub fn main() !void {
const out = std.io.getStdOut().writer();
const A = struct { pub const label: []const u8 = "basic"; v: u32 = 1 };
const B = struct { v: u32 = 1 };
try out.print("hasA={}\n", .{@hasDecl(A, "label")});
try out.print("hasB={}\n", .{@hasDecl(B, "label")});
}
A label with a default
A function can return the stored label when it exists and a default word when it does not.
fn labelOf(comptime T: type) []const u8 {
if (@hasDecl(T, "label")) {
return T.label;
}
return "unknown";
}
const std = @import("std");
pub fn main() !void {
const out = std.io.getStdOut().writer();
const A = struct { pub const label: []const u8 = "alpha"; };
const B = struct { v: u32 = 0 };
try out.print("a={s}\n", .{labelOf(A)});
try out.print("b={s}\n", .{labelOf(B)});
}
Fields are not declarations
A struct field looks like a named item, but @hasDecl reports false for it because a field is not a declaration.
const std = @import("std");
pub fn main() !void {
const out = std.io.getStdOut().writer();
const Point = struct { x: i32, y: i32 };
try out.print("hasX={}\n", .{@hasDecl(Point, "x")});
try out.print("hasLabel={}\n", .{@hasDecl(Point, "label")});
}
Example
fn labelOf(comptime T: type) []const u8 {
if (@hasDecl(T, "label")) {
return T.label;
}
return "unknown";
}
fn limitOf(comptime T: type) u32 {
if (@hasDecl(T, "limit")) {
return T.limit;
}
return 0;
}
const std = @import("std");
pub fn main() !void {
const out = std.io.getStdOut().writer();
const Fast = struct { pub const label: []const u8 = "fast"; pub const limit: u32 = 10; };
const Slow = struct { v: u32 = 0 };
try out.print("fast-label={s}\n", .{labelOf(Fast)});
try out.print("fast-limit={d}\n", .{limitOf(Fast)});
try out.print("slow-label={s}\n", .{labelOf(Slow)});
try out.print("slow-limit={d}\n", .{limitOf(Slow)});
}
Key points
- Comptime branch: a comptime branch is a branch whose condition is known during compilation.
- Declaration: a declaration is a named constant stored inside a container.
- HasDecl: @hasDecl is a builtin that reports whether a type holds a declaration with a given name.
- Default: a default is the value used when the named declaration is absent.
- Label: a label is a short text name stored as a declaration inside a type.
The example checks two types for label and limit declarations. The first type stores both, so both stored values print. The second type stores neither, so both default values print instead.
Try it Yourself
Edit the code, then press Run.
Running is simulated
Exercise
What does @hasDecl(Point, "x") return when x is a field of Point?