# Appendix H. Zig 0.16 Migration Notes

### Appendix H. Zig 0.16 Migration Notes

This appendix records the kinds of changes that matter when moving older Zig code to Zig 0.16. It is a practical checklist, not a full release history.

### H.1 Start With the Compiler

Run the new compiler first.

```sh
zig version
zig build
zig test src/main.zig
```

Fix errors in this order:

1. build script errors
2. import and module errors
3. standard library API errors
4. type and builtin errors
5. runtime behavior changes

Do not rewrite the program before reading the first compiler error.

### H.2 Build Script Changes

Old build scripts usually fail before source files compile.

Check:

```zig
pub fn build(b: *std.Build) void {
    const target = b.standardTargetOptions(.{});
    const optimize = b.standardOptimizeOption(.{});
}
```

Artifacts should receive `.target` and `.optimize`.

```zig
const exe = b.addExecutable(.{
    .name = "app",
    .root_source_file = b.path("src/main.zig"),
    .target = target,
    .optimize = optimize,
});
```

Use `b.path(...)` for project-relative paths.

```zig
.root_source_file = b.path("src/main.zig")
```

### H.3 Modules and Imports

Prefer explicit modules.

```zig
const lib_mod = b.createModule(.{
    .root_source_file = b.path("src/lib.zig"),
    .target = target,
    .optimize = optimize,
});

exe.root_module.addImport("lib", lib_mod);
```

Then import by name:

```zig
const lib = @import("lib");
```

This is cleaner than relying on path-shaped imports throughout the program.

### H.4 Package Dependencies

Use `build.zig.zon` for package metadata and dependencies.

Typical project files:

```text
build.zig
build.zig.zon
src/main.zig
```

A dependency is read in `build.zig`.

```zig
const dep = b.dependency("name", .{
    .target = target,
    .optimize = optimize,
});

exe.root_module.addImport("name", dep.module("name"));
```

Source files import the module.

```zig
const name = @import("name");
```

### H.5 Standard Library Movement

The standard library changes between Zig versions. Treat `std` as source code you can inspect.

Search by name:

```sh
grep -R "pub fn openFile" "$(zig env | jq -r .std_dir)"
```

Or open the standard library directory:

```sh
zig env
```

Common areas that may need edits:

```text
std.fs
std.io
std.mem
std.process
std.Build
std.http
std.json
```

When an API changed, do not guess the replacement from memory. Read the new declaration.

### H.6 I/O Code

I/O APIs are common migration points.

Old code often has one of these shapes:

```zig
const stdout = std.io.getStdOut().writer();
try stdout.print("hello\n", .{});
```

or file reading code like:

```zig
const data = try file.readToEndAlloc(allocator, max_size);
```

Check Zig 0.16 declarations directly if these fail. I/O is an area where names and interfaces may move during standard library work.

### H.7 Memory Utilities

Check old memory calls.

```zig
std.mem.copy
std.mem.set
```

Modern code commonly uses more explicit names or builtins.

```zig
std.mem.copyForwards
std.mem.copyBackwards
@memcpy
@memset
```

Use `copyForwards` or `copyBackwards` when overlap direction matters. Use `@memcpy` when the source and destination must not overlap.

### H.8 Integer Casts

Older code may use casts that no longer match the current builtin signatures.

Prefer destination type from context:

```zig
const x: u32 = @intCast(n);
```

Use `@as` when the result type is not clear from context.

```zig
const x = @as(u32, @intCast(n));
```

Do the same for floats and enum conversion where needed.

### H.9 Pointer Casts

Pointer casts should be explicit about intent.

```zig
const p: *T = @ptrCast(raw);
```

If alignment increases, add `@alignCast`.

```zig
const p: *T = @alignCast(@ptrCast(raw));
```

If the conversion changes constness, fix the type instead of forcing the cast.

### H.10 Error Handling

Old code may ignore errors.

```zig
file.writeAll(data);
```

Zig rejects this.

```zig
try file.writeAll(data);
```

Or handle the error locally.

```zig
file.writeAll(data) catch |err| {
    return err;
};
```

Do not silence errors with `catch {}` unless losing the error is correct.

### H.11 Optional Handling

Check old null-handling code.

```zig
const value = maybe.?;
```

A force unwrap is acceptable only when null means a programmer bug.

Safer forms:

```zig
const value = maybe orelse return error.MissingValue;
```

```zig
if (maybe) |value| {
    use(value);
}
```

### H.12 `comptime` Code

Compile-time code may break because of stricter type checking or changed reflection shapes.

Common places:

```zig
@typeInfo
@Type
@hasDecl
@hasField
@field
inline for
```

Keep compile-time code small. Print intermediate values with:

```zig
@compileLog(x);
```

Remove `@compileLog` after the migration.

### H.13 Tests

Run all tests after each group of edits.

```sh
zig build test
zig test src/main.zig
```

Use `std.testing.allocator` in tests that allocate.

```zig
const allocator = std.testing.allocator;
```

Free what you allocate.

```zig
const buf = try allocator.alloc(u8, 1024);
defer allocator.free(buf);
```

### H.14 C Interop

Check C interop in three places:

```text
@cImport blocks
extern declarations
build.zig linking
```

Build script:

```zig
exe.linkLibC();
exe.addIncludePath(b.path("include"));
exe.linkSystemLibrary("sqlite3");
```

C declaration:

```zig
extern fn puts(s: [*:0]const u8) c_int;
```

When translated headers fail, reduce the header surface. Import the smallest C header that gives the declarations you need.

### H.15 Release Modes

Check behavior in all modes that the project supports.

```sh
zig build -Doptimize=Debug
zig build -Doptimize=ReleaseSafe
zig build -Doptimize=ReleaseFast
zig build -Doptimize=ReleaseSmall
```

Debug and ReleaseSafe keep more safety checks. ReleaseFast and ReleaseSmall remove many checks.

Do not rely on a safety trap as part of normal program behavior.

### H.16 Migration Checklist

Use this order:

```text
1. install Zig 0.16
2. run zig version
3. run zig build
4. fix build.zig
5. fix modules and imports
6. fix standard library API calls
7. fix builtin calls and casts
8. fix error handling
9. run tests
10. run release builds
```

A good migration leaves the code simpler than before. Delete compatibility wrappers once all code uses the new form.

