about things
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

at main 104 lines 2.9 kB view raw view rendered
1# interfaces 2 3zig has no interfaces or traits. use comptime patterns instead. 4 5## anytype with validation 6 7accept `anytype` and validate at comptime: 8 9```zig 10fn process(db: anytype) !void { 11 const T = @TypeOf(db); 12 if (!@hasDecl(T, "exec")) { 13 @compileError("db must have exec method"); 14 } 15 try db.exec("SELECT 1", .{}); 16} 17``` 18 19this is the simplest approach - compiler verifies the type has required methods. 20 21## type-returning functions 22 23for generic wrappers, return a type that delegates to an implementation: 24 25```zig 26pub fn DatabaseInterface(comptime Impl: type) type { 27 return struct { 28 impl: Impl, 29 30 const Self = @This(); 31 32 pub fn exec(self: Self, sql: []const u8, args: anytype) !void { 33 return self.impl.exec(sql, args); 34 } 35 }; 36} 37``` 38 39useful when you want a consistent outer API regardless of implementation. 40 41## vtables for runtime dispatch 42 43when you need runtime polymorphism (rare in zig): 44 45```zig 46pub const Database = struct { 47 ptr: *anyopaque, 48 vtable: *const VTable, 49 50 const VTable = struct { 51 exec: *const fn (*anyopaque, []const u8) anyerror!void, 52 }; 53 54 pub fn exec(self: Database, sql: []const u8) !void { 55 return self.vtable.exec(self.ptr, sql); 56 } 57}; 58``` 59 60this is the std.io.Writer pattern. more boilerplate, but allows swapping implementations at runtime. 61 62## comptime-parameterized adapter 63 64when you need a struct that bridges between a library's callback interface and a user's handler type, return a type parameterized on the handler: 65 66```zig 67fn WsHandler(comptime H: type) type { 68 return struct { 69 allocator: Allocator, 70 handler: *H, 71 client_state: *FirehoseClient, 72 73 const Self = @This(); 74 75 pub fn serverMessage(self: *Self, data: []const u8) !void { 76 var arena = std.heap.ArenaAllocator.init(self.allocator); 77 defer arena.deinit(); 78 79 const event = decodeFrame(arena.allocator(), data) catch return; 80 self.handler.onEvent(event); 81 } 82 83 pub fn close(_: *Self) void {} 84 }; 85} 86``` 87 88this adapts the websocket library's `serverMessage` callback to our firehose handler's `onEvent` interface. the comptime parameter `H` is the user's handler type — the compiler generates a specialized struct for each handler type used. no vtables, no allocation, full inlining. 89 90see: [zat/firehose.zig](https://tangled.sh/@zzstoatzz.io/zat/tree/main/src/internal/firehose.zig) 91 92## practical: module boundary pattern 93 94for most apps, just separate interface documentation from implementation: 95 96``` 97db/ 98 mod.zig -- re-exports, expected methods documented in comments 99 sqlite.zig -- sqlite implementation 100``` 101 102the "interface" is implicit - documented expectations in `mod.zig`, verified by usage at compile time. 103 104see: [comptime](./comptime.md), [database](./database.md)