comptime sql bindings for zig
ziglang
sql
1# zig comptime
2
3internal research on zig's compile-time execution for informing zql's design.
4
5## core mechanisms
6
7### comptime parameters (generics)
8
9functions accept `comptime` parameters that must be known at compile time:
10
11```zig
12fn max(comptime T: type, a: T, b: T) T {
13 return if (a > b) a else b;
14}
15```
16
17this implements compile-time duck typing - if `T` doesn't support `>`, error at call site.
18
19### comptime variables
20
21```zig
22comptime var y: i32 = 1;
23y += 1; // evaluated during compilation
24```
25
26### inline loops
27
28`inline for` and `inline while` unroll at compile time:
29
30```zig
31inline for (std.meta.fields(T)) |field| {
32 @field(value, field.name) = processField(field);
33}
34```
35
36## type-level programming
37
38types are first-class values at comptime. functions can return types:
39
40```zig
41fn ArrayList(comptime T: type) type {
42 return struct {
43 items: []T,
44 len: usize,
45
46 const Self = @This();
47
48 fn append(self: *Self, item: T) !void {
49 // ...
50 }
51 };
52}
53```
54
55## reflection via @typeInfo
56
57inspect type structure at compile time:
58
59```zig
60fn GetBiggerInt(comptime T: type) type {
61 const info = @typeInfo(T).Int;
62 return @Type(.{
63 .Int = .{
64 .bits = info.bits + 1,
65 .signedness = info.signedness,
66 },
67 });
68}
69```
70
71## key builtins
72
73| builtin | purpose |
74|---------|---------|
75| `@typeInfo(T)` | returns tagged union describing type structure |
76| `@Type(info)` | reifies a type from `@typeInfo` output |
77| `@TypeOf(expr)` | returns expression's type |
78| `@field(obj, name)` | dynamic field access (name must be comptime) |
79| `@hasField(T, name)` | checks if type has named field |
80| `@hasDecl(T, name)` | checks if type has named declaration |
81| `@compileError(msg)` | generates compile error with custom message |
82
83## std.meta utilities
84
85- `std.meta.fields(T)` - returns struct/union/enum field information
86- `std.meta.fieldNames(T)` - returns slice of field name strings
87- `std.meta.FieldEnum(T)` - generates enum matching struct fields
88- `std.meta.hasFn(T, name)` - checks if type has a function declaration
89- `std.meta.eql(a, b)` - recursive structural equality
90- `std.meta.Tuple(&types)` - creates tuple type from array of types
91
92## limitations
93
94| limitation | reason | workaround |
95|------------|--------|------------|
96| no I/O | hermetic, reproducible builds | use `build.zig` for external I/O |
97| no heap allocation | currently unsupported | proposals exist (#5873, #5881) |
98| `@Type` incomplete | not implemented for enums, unions, functions | use simpler type construction |
99| no runtime type info | types only exist at comptime | build custom RTTI at comptime |
100
101## gotchas
102
1031. **comptime doesn't cross function boundaries** without explicit marking
1042. **`@field` requires comptime-known strings** - can't use runtime strings
1053. **comptime pollution** - once something is comptime, everything it uses must be too
1064. **branch quota** - loops default to 1000 backward branches, use `@setEvalBranchQuota()`
1075. **no declaration-site type checking** - errors appear at call sites, not generic definitions
108
109## patterns relevant to zql
110
111### comptime string parsing
112
113std.fmt parses format strings at comptime, validating types before runtime:
114
115```zig
116std.debug.print("Value: {d}, Name: {s}\n", .{ value, name });
117// format string parsed at compile time; type mismatches caught during compilation
118```
119
120this is what zql does with SQL strings.
121
122### perfect hash generation
123
124andrew kelley demonstrated O(1) string switches via comptime perfect hash search:
125
126```zig
127const ph = perfectHash(&.{ "a", "ab", "abc" });
128switch (ph.hash(target)) {
129 ph.case("a") => handleA(),
130 ph.case("ab") => handleAb(),
131 else => unreachable,
132}
133```
134
135could be useful for column name lookups.
136
137### comptime string interning
138
139leverage memoization to deduplicate strings:
140
141```zig
142fn internString(comptime str: []const u8) []const u8 {
143 return internStringBuffer(str.len, str[0..str.len].*);
144}
145
146fn internStringBuffer(comptime len: comptime_int, comptime items: [len]u8) []const u8 {
147 comptime var storage: [len]u8 = items;
148 return &storage;
149}
150```
151
152since comptime calls are memoized, identical strings return the same address.
153
154### schema/orm patterns (tigerbeetle)
155
156```zig
157fn DBType(comptime schema: Schema) type {
158 return struct {
159 tables: generateTables(schema),
160 indexes: generateIndexes(schema),
161
162 pub fn query(self: *@This(), comptime filter: Filter) Iterator {
163 // ...
164 }
165 };
166}
167```
168
169this is where zql could go - define schema once, generate queries.
170
171## sources
172
173### official
174- [zig language reference - comptime](https://ziglang.org/documentation/master/#comptime)
175
176### andrew kelley
177- [string matching based on compile time perfect hashing](https://andrewkelley.me/post/string-matching-comptime-perfect-hashing-zig.html)
178- [zig blurs the line between compile-time and run-time](https://andrewkelley.me/post/zig-programming-language-blurs-line-compile-time-run-time.html)
179
180### community
181- [what is zig's comptime? - loris cro](https://kristoff.it/blog/what-is-zig-comptime/)
182- [comptime zig orm - matklad](https://matklad.github.io/2025/03/19/comptime-zig-orm.html)
183- [things zig comptime won't do - matklad](https://matklad.github.io/2025/04/19/things-zig-comptime-wont-do.html)
184- [zig metaprogramming - openmymind](https://www.openmymind.net/Basic-MetaProgramming-in-Zig/)
185
186### std library source
187- [std/meta.zig](https://github.com/ziglang/zig/blob/master/lib/std/meta.zig)
188- [std/fmt.zig](https://github.com/ziglang/zig/blob/master/lib/std/fmt.zig)