Expert systems programming assistance for the Zig programming language. Use when writing, debugging, optimizing, or explaining Zig code. Triggers include requests to write Zig programs, debug Zig compilation errors, explain Zig language features (comptime, error handling, memory management), create build.zig files, work with the standard library, optimize Zig code, or convert code from other languages to Zig. Provides idiomatic patterns, build system guidance, and comprehensive language expertise.
Expert assistance for systems programming with Zig - a general-purpose programming language focused on robustness, optimality, and maintainability.
When writing Zig code, follow these fundamental principles:
comptime for zero-cost abstractionsconst std = @import("std");
pub fn main(init: std.process.Init) !void {
std.debug.print("Hello, {s}!\n", .{"World"});
}
Error handling with try:
const file = try std.fs.cwd().openFile("data.txt", .{});
defer file.close();
Memory allocation:
const allocator = std.heap.page_allocator;
const items = try allocator.alloc(u32, 10);
defer allocator.free(items);
Comptime generics:
fn max(comptime T: type, a: T, b: T) T {
return if (a > b) a else b;
}
Zig uses explicit error handling with error unions (!):
// Function that may fail
fn divide(a: f64, b: f64) !f64 {
if (b == 0) return error.DivisionByZero;
return a / b;
}
// Using try to propagate errors
const result = try divide(10, 2);
// Using catch to handle errors
const result = divide(10, 0) catch |err| {
std.debug.print("Error: {}\n", .{err});
return;
};
// Using if to check for errors
if (divide(10, 2)) |value| {
std.debug.print("Success: {}\n", .{value});
} else |err| {
std.debug.print("Error: {}\n", .{err});
}
Always pass allocators explicitly and use defer for cleanup:
fn processData(allocator: std.mem.Allocator) !void {
var list = std.ArrayList(i32).init(allocator);
defer list.deinit();
try list.append(42);
// list automatically freed on function exit
}
Arena allocator for bulk operations:
var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator);
defer arena.deinit();
const allocator = arena.allocator();
// All allocations freed on arena.deinit()
const data1 = try allocator.alloc(u8, 100);
const data2 = try allocator.alloc(u8, 200);
Use comptime for compile-time code execution:
// Generic data structures
fn List(comptime T: type) type {
return struct {
items: []T,
len: usize,
pub fn init(allocator: std.mem.Allocator, capacity: usize) !@This() {
return .{
.items = try allocator.alloc(T, capacity),
.len = 0,
};
}
};
}
// Type introspection
fn printFieldNames(comptime T: type) void {
inline for (@typeInfo(T).Struct.fields) |field| {
std.debug.print("Field: {s}\n", .{field.name});
}
}
Handle nullable values with ? and orelse:
const maybe_value: ?i32 = null;
// Provide default value
const value = maybe_value orelse 42;
// Check and unwrap
if (maybe_value) |v| {
std.debug.print("Value: {}\n", .{v});
} else {
std.debug.print("No value\n", .{});
}
const Point = struct {
x: f64,
y: f64,
pub fn init(x: f64, y: f64) Point {
return .{ .x = x, .y = y };
}
pub fn distance(self: Point, other: Point) f64 {
const dx = self.x - other.x;
const dy = self.y - other.y;
return @sqrt(dx * dx + dy * dy);
}
};
const p1 = Point.init(0, 0);
const p2 = Point{ .x = 3, .y = 4 };
const dist = p1.distance(p2);
const Value = union(enum) {
int: i64,
float: f64,
string: []const u8,
pub fn print(self: Value) void {
switch (self) {
.int => |i| std.debug.print("int: {}\n", .{i}),
.float => |f| std.debug.print("float: {}\n", .{f}),
.string => |s| std.debug.print("string: {s}\n", .{s}),
}
}
};
Every Zig project needs a build.zig file:
const std = @import("std");
pub fn build(b: *std.Build) void {
const target = b.standardTargetOptions(.{});
const optimize = b.standardOptimizeOption(.{});
const exe = b.addExecutable(.{
.name = "myapp",
.root_source_file = b.path("src/main.zig"),
.target = target,
.optimize = optimize,
});
b.installArtifact(exe);
const run_cmd = b.addRunArtifact(exe);
const run_step = b.step("run", "Run the app");
run_step.dependOn(&run_cmd.step);
// Add tests
const tests = b.addTest(.{
.root_source_file = b.path("src/main.zig"),
.target = target,
.optimize = optimize,
});
const test_step = b.step("test", "Run tests");
test_step.dependOn(&b.addRunArtifact(tests).step);
}
zig build # Build the project
zig build run # Run the executable
zig build test # Run tests
zig build -Doptimize=ReleaseFast # Build optimized
For detailed build system patterns, see references/build_system.md.
Write tests using the test keyword:
const std = @import("std");
const testing = std.testing;
test "basic arithmetic" {
try testing.expect(2 + 2 == 4);
try testing.expectEqual(@as(i32, 42), 42);
}
test "with allocator" {
var arena = std.heap.ArenaAllocator.init(testing.allocator);
defer arena.deinit();
const allocator = arena.allocator();
const items = try allocator.alloc(i32, 5);
try testing.expectEqual(@as(usize, 5), items.len);
}
Run with: zig test src/main.zig
Use the provided script to scaffold a new project:
python scripts/init_project.py myproject
cd myproject
zig build run
// Read file
const file = try std.fs.cwd().openFile("data.txt", .{});
defer file.close();
const content = try file.readToEndAlloc(allocator, 1_000_000);
defer allocator.free(content);
// Write file
const out = try std.fs.cwd().createFile("output.txt", .{});
defer out.close();
try out.writeAll("Hello, World!\n");
// String formatting
const str = try std.fmt.allocPrint(allocator, "Value: {}", .{42});
defer allocator.free(str);
// Parsing
const num = try std.fmt.parseInt(i32, "123", 10);
// String comparison
const equal = std.mem.eql(u8, str1, str2);
// String splitting
var iter = std.mem.split(u8, "a,b,c", ",");
while (iter.next()) |part| {
// Process part
}
// ArrayList
var list = std.ArrayList(i32).init(allocator);
defer list.deinit();
try list.append(42);
// HashMap
var map = std.StringHashMap(i32).init(allocator);
defer map.deinit();
try map.put("key", 42);
const value = map.get("key");
@as(TargetType, value) or @intCast(value)return, break, or other control flowtrydeferstd.testing.allocator which detects leakszig build -Doptimize=ReleaseFastzig build -Doptimize=ReleaseFast with profiling toolsinline to small, frequently-called functionsThis skill includes comprehensive reference materials:
references/common_patterns.md: Idiomatic Zig patterns for error handling, memory management, comptime programming, testing, and morereferences/build_system.md: Complete build.zig patterns, cross-compilation, dependencies, and build configurationsreferences/stdlib_essentials.md: Standard library usage guide covering allocators, data structures, I/O, strings, JSON, and testing utilitiesLoad these references when working on specific aspects of Zig programming.
scripts/init_project.py: Scaffold a new Zig project with proper structure, build.zig, and basic setup