comptime sql bindings for zig
ziglang sql
at main 188 lines 5.6 kB view raw view rendered
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)