# Appendix A. Zig 1.16 New Features

## Appendix A. Zig 1.16 New Features

As of the current public Zig release line, the version is Zig 0.16, not Zig 1.16. Zig has not reached 1.0 yet. In this appendix, read “Zig 1.16” as “Zig 0.16” unless you are using a future release.

This appendix is a migration and review chapter. It is not meant to teach every feature from scratch. It collects the areas you should check when moving code to Zig 0.16.

### A.1 What to Check First

When upgrading a Zig project, check these areas first:

```text
build.zig
standard library imports
I/O APIs
allocator usage
container APIs
builtin functions
test commands
dependency declarations
```

Most Zig version upgrades affect code in these places before they affect ordinary arithmetic, structs, enums, or control flow.

### A.2 Build System Changes

Zig projects usually depend on `build.zig`.

A simple executable project has this shape:

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

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

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

    b.installArtifact(exe);
}
```

When a release changes the build system, old projects usually fail at compile time with clear errors. Fix `build.zig` first. After the build file works, move on to application code.

### A.3 Standard Library API Movement

Zig’s standard library is still evolving.

That means names may move, signatures may change, and some helper functions may be replaced by clearer versions.

When this happens, do not guess. Use the compiler error as the guide.

For example, if old code says:

```zig
var list = std.ArrayList(u8).init(allocator);
```

and the compiler rejects it, inspect the new `std.ArrayList` API for the exact constructor and ownership rules.

The important habit is this: treat the standard library as source code you can read. Zig makes that practical.

### A.4 I/O API Review

Many beginner programs use stdout, stderr, and file readers.

A modern Zig style often creates a buffered writer, writes through its interface, then flushes:

```zig
var buffer: [1024]u8 = undefined;
var writer = std.fs.File.stdout().writer(&buffer);
const stdout = &writer.interface;

try stdout.print("hello\n", .{});
try stdout.flush();
```

The key rule is simple: writing into a buffer is not enough. Flush when you need the output to appear.

### A.5 Allocator Review

Allocator-heavy code should be checked carefully during upgrades.

Look for:

```text
ArrayList creation
HashMap creation
arena usage
owned slice conversion
manual frees
errdefer cleanup
```

The pattern remains the same:

```zig
var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator);
defer arena.deinit();

const allocator = arena.allocator();
```

Use arenas when many allocations share one lifetime. Use a general-purpose allocator when objects have mixed lifetimes.

### A.6 Builtins

Builtins begin with `@`.

Examples:

```zig
@import
@sizeOf
@alignOf
@intCast
@ptrCast
@bitCast
@memcpy
@memset
@compileError
```

Upgrades often make builtin usage stricter. That is usually good. It means the compiler needs less guessing from context.

When a builtin call breaks, check:

```text
number of arguments
result type
whether the destination type is inferred
whether the cast is still allowed
```

### A.7 Error Handling Still Looks the Same

The core error model remains stable:

```zig
fn readConfig() !Config {
    return error.MissingConfig;
}
```

Calling code handles errors with:

```zig
const config = try readConfig();
```

or:

```zig
const config = readConfig() catch |err| {
    std.debug.print("error: {s}\n", .{@errorName(err)});
    return err;
};
```

This is one of Zig’s central design points: failure stays visible in the type.

### A.8 Comptime Still Matters

Generic code still often uses `comptime`:

```zig
fn add(comptime T: type, a: T, b: T) T {
    return a + b;
}
```

The compiler evaluates `T` at compile time, then creates code for the concrete type.

This remains one of the main differences between Zig and C.

### A.9 Migration Strategy

Do not upgrade a large Zig project randomly.

Use this order:

```text
1. upgrade Zig
2. run zig build
3. fix build.zig
4. fix imports and standard library API errors
5. fix builtin/cast errors
6. run tests
7. inspect warnings or behavior changes
8. update docs and examples
```

Keep each fix small. Build often.

### A.10 What This Appendix Is For

This appendix gives you a checklist, not a complete changelog.

For exact release details, always read the official Zig release notes and the source code for the standard library version you are using.

The practical rule is simple: Zig upgrades are compiler-guided. Build the project, read the first error, fix it, then repeat.

