defer and errdefer

Deferred statements run in reverse order at block exit (not function exit, unlike Go).

errdefer |err| log(err); captures the error.

Pair every resource acquisition with an immediate defer/errdefer. This is Zig's alternative to RAII.

fn processFile(allocator: std.mem.Allocator, path: []const u8) !void {
    const file = try std.fs.cwd().openFile(path, .{});
    defer file.close();                          // runs at scope exit (always)

    const buf = try allocator.alloc(u8, 4096);
    defer allocator.free(buf);

    // ... use file and buf
}

fn createUser(allocator: std.mem.Allocator, name: []const u8) !*User {
    const user = try allocator.create(User);
    errdefer allocator.destroy(user);           // runs ONLY if the function returns an error

    user.name = try allocator.dupe(u8, name);
    errdefer allocator.free(user.name);

    try registerUser(user);                     // if this fails, both errdefers run
    return user;                                // success: errdefers are skipped
}