Zig 0.16 API Gotchas
Zig 0.16 API Gotchas
Section titled “Zig 0.16 API Gotchas”Janus targets: 0.16.0-dev.2964+10256e1b8
Last updated: 2026-03-30
When writing or modifying Janus compiler code (Zig), these patterns will cause compile errors. This is a living document—add new gotchas as we discover them.
1. std.io → std.Io (Capital I)
Section titled “1. std.io → std.Io (Capital I)”Zig 0.16 reorganized the I/O module. The lowercase io is gone.
// ❌ DOES NOT COMPILEconst stdout = std.io.getStdOut().writer();
// ✅ CORRECTconst stdout = std.Io.File.stdout().writer();2. ArrayList.writer() Removed
Section titled “2. ArrayList.writer() Removed”Zig 0.16 removed .writer() from ArrayList. Use the BufWriter pattern instead.
// ❌ DOES NOT COMPILEvar output = std.ArrayList(u8).init(allocator);defer output.deinit();const writer = output.writer();
// ✅ CORRECT — BufWriter adapterconst BufWriter = struct { buf: *std.ArrayList(u8), alloc: std.mem.Allocator,
pub fn print(self: BufWriter, comptime fmt: []const u8, args: anytype) !void { var tmp: [4096]u8 = undefined; const result = std.fmt.bufPrint(&tmp, fmt, args) catch return error.NoSpaceLeft; try self.buf.appendSlice(self.alloc, result); }
pub fn writeAll(self: BufWriter, data: []const u8) !void { try self.buf.appendSlice(self.alloc, data); }};
var output: std.ArrayList(u8) = .empty;try output.ensureTotalCapacity(allocator, 4096);defer output.deinit(allocator);const writer = bufWriter(&output, allocator);
fn bufWriter(buf: *std.ArrayList(u8), allocator: std.mem.Allocator) BufWriter { return BufWriter{ .buf = buf, .alloc = allocator };}Existing reference implementations:
compiler/inspect/dumper.zig—BufWriterstructcmd/janusd/json_helpers.zig—ArrayListWriter
3. ArrayList.init() Removed (Use .empty)
Section titled “3. ArrayList.init() Removed (Use .empty)”The .init() constructor was removed in favor of .empty literal.
// ❌ DOES NOT COMPILEvar list = std.ArrayList(u8).init(allocator);
// ✅ CORRECTvar list: std.ArrayList(u8) = .empty;try list.ensureTotalCapacity(allocator, 256);defer list.deinit(allocator);4. std.fs.cwd() File Operations → compat_fs
Section titled “4. std.fs.cwd() File Operations → compat_fs”Direct filesystem operations on std.fs.cwd() don’t work the same way. Use the Janus compat_fs module instead.
// ❌ DOES NOT COMPILEconst source = std.fs.cwd().readFileAlloc(allocator, path, size);std.fs.cwd().writeFile(path, data);
// ✅ CORRECTconst source = compat_fs.readFileAlloc(allocator, path, size);try compat_fs.writeFile(.{ .sub_path = path, .data = data });Note: The compat_fs module must be imported explicitly:
const compat_fs = @import("compat_fs");And added to the module’s build.zig imports:
janus_cli.root_module.addImport("compat_fs", b.addModule("compat_fs", .{ .root_source_file = b.path("runtime/compat/fs.zig"), .target = target, .optimize = optimize,}));5. deinit() Now Requires Allocator
Section titled “5. deinit() Now Requires Allocator”ArrayList.deinit() now takes an allocator parameter.
// ❌ COMPILE WARNING (will change)defer list.deinit();
// ✅ CORRECTdefer list.deinit(allocator);6. append() Now Takes Allocator
Section titled “6. append() Now Takes Allocator”All mutation operations on ArrayList now require explicit allocator.
// ❌ DOES NOT COMPILEtry list.append(item);
// ✅ CORRECTtry list.append(allocator, item);
// ❌ DOES NOT COMPILEtry list.appendSlice(items);
// ✅ CORRECTtry list.appendSlice(allocator, items);7. Enum Formatting with @tagName()
Section titled “7. Enum Formatting with @tagName()”Passing enum values directly to {s} format specifier doesn’t work.
// ❌ DOES NOT COMPILE — JanusType is an enumtry writer.print("type: {s}", .{some_janus_type});
// ✅ CORRECT — use @tagName()try writer.print("type: {s}", .{@tagName(some_janus_type)});8. std.Io Requires Explicit Context
Section titled “8. std.Io Requires Explicit Context”std.Io is no longer a simple namespace—it requires an Io instance for many operations.
// ❌ WON'T WORK as expectedconst file = std.Io.File.stdout();
// ✅ MAY NEED context depending on usage// For simple stdout writing, prefer std.debug.print() insteadstd.debug.print("{s}", .{output.items});Quick Reference: Safe Patterns
Section titled “Quick Reference: Safe Patterns”| Operation | Old (0.14) | New (0.16) |
|---|---|---|
| Create ArrayList | .init(allocator) | .empty + ensureTotalCapacity |
| Deallocate | deinit() | deinit(allocator) |
| Append item | append(item) | append(allocator, item) |
| Get writer | .writer() | Use BufWriter adapter |
| Stdout | std.io.getStdOut() | std.Io.File.stdout() |
| Read file | cwd().readFileAlloc() | compat_fs.readFileAlloc() |
| Write file | cwd().writeFile() | compat_fs.writeFile(.{.sub_path, .data}) |
Related
Section titled “Related”- ADR-002: ArrayList Migration — Historical context
- REFRACTOR-ZIG-0.16-PLAN.md — Migration plan
compiler/inspect/dumper.zig— Real-worldBufWriterexamplecmd/janusd/json_helpers.zig—ArrayListWriterexample