# 0.16 migration notes verified with `zig-aarch64-macos-0.16.0-dev.2296+fd3657bf8` ## high-impact changes - **std.net removed** - networking now via `Io.net` - **std.crypto.random removed** - randomness now via `io.random()` - **std.Thread.Pool removed** - use `Io.Group` with `Io.Threaded` - **posix.shutdown removed** - use `std.c.shutdown(fd, how)` - **posix.getrandom removed** - use `io.random()` these require significant refactoring as they move to the Io-based paradigm. ## build.zig changes `linkLibC()` removed. use module options instead: ```zig // 0.15 const exe = b.addExecutable(.{...}); exe.linkLibC(); // 0.16 const exe = b.addExecutable(.{ .name = "myapp", .root_module = b.createModule(.{ .root_source_file = b.path("src/main.zig"), .target = target, .optimize = optimize, .link_libc = true, // here }), }); ``` ## package hashes 0.16 calculates hashes differently. compiler will tell you the correct hash. ## removed APIs ### std.time.timestamp() / milliTimestamp() use libc directly: ```zig const c = std.c; pub fn timestamp() i64 { var tv: c.timeval = undefined; _ = c.gettimeofday(&tv, null); return tv.sec; } pub fn milliTimestamp() i64 { var tv: c.timeval = undefined; _ = c.gettimeofday(&tv, null); return @as(i64, tv.sec) * 1000 + @divTrunc(@as(i64, tv.usec), 1000); } ``` ### std.Thread.sleep() use libc nanosleep: ```zig pub fn sleep(ns: u64) void { const secs = ns / std.time.ns_per_s; const nsecs = ns % std.time.ns_per_s; var ts: std.c.timespec = .{ .sec = @intCast(secs), .nsec = @intCast(nsecs), }; _ = std.c.nanosleep(&ts, null); } ``` ### std.posix.getenv() use `std.c.getenv()` with `std.mem.span()`: ```zig // 0.15 const val = std.posix.getenv("FOO") orelse "default"; // 0.16 - returns [*:0]const u8, not slice const val = if (std.c.getenv("FOO")) |p| std.mem.span(p) else "default"; ``` ### @Type builtin removed. use specific type builtins: ```zig // 0.15 const Args = @Type(.{ .@"struct" = .{ .is_tuple = true, ... } }); // 0.16 const Args = @Tuple(&field_types); // or @Struct(...) for non-tuples ``` ### posix.shutdown use libc directly: ```zig // 0.15 posix.shutdown(fd, .recv) catch {}; // 0.16 _ = std.c.shutdown(fd, 0); // SHUT_RD = 0, SHUT_WR = 1, SHUT_RDWR = 2 ``` ### std.testing.expectEqual argument order changed (minor but affects all tests): ```zig // 0.15 try std.testing.expectEqual(@as(@TypeOf(actual), expected), actual); // 0.16 - simpler, expected comes first naturally try std.testing.expectEqual(expected, actual); ``` ## networking `std.net` is gone. use `Io.net`: ```zig const Io = std.Io; const net = Io.net; // connecting to a host pub fn connect(io: Io, host: []const u8, port: u16) !net.Stream { const host_name = try net.HostName.init(host); return host_name.connect(io, port, .{}); } ``` **note**: `Io.net.Stream` no longer has direct `read`/`writeAll` methods. you need to create `Stream.Reader` or `Stream.Writer` wrappers: ```zig // reading from stream requires a Reader wrapper pub fn readFromStream(stream: net.Stream, io: Io, buffer: []u8) !usize { var reader = net.Stream.Reader.init(stream, io, buffer); // use reader.interface for reading return reader.interface.read(buffer); } ``` `net.Address` → `net.IpAddress`: ```zig // 0.15 const addr = std.net.Address.parseIp("127.0.0.1", 8080); // 0.16 const addr = Io.net.IpAddress.parse("127.0.0.1", 8080); ``` ## randomness `std.crypto.random` removed. use `io.random()`: ```zig // 0.15 var bytes: [16]u8 = undefined; std.crypto.random.bytes(&bytes); // 0.16 - io.random() returns typed value directly const io = std.Options.debug_io; const bytes: [16]u8 = io.random(); // returns [16]u8 directly const seed: u64 = io.random(); // returns u64 directly ``` ## file I/O file ops now take `io: Io` parameter. get default io from `std.Options.debug_io`: ```zig const std = @import("std"); const Io = std.Io; pub fn readFile(path: []const u8) ![]u8 { const io = std.Options.debug_io; const file = try Io.Dir.openFileAbsolute(io, path, .{}); defer file.close(io); var buf: [4096]u8 = undefined; const n = try file.readPositional(io, &.{&buf}, 0); return buf[0..n]; } pub fn writeFile(path: []const u8, data: []const u8) !void { const io = std.Options.debug_io; const file = try Io.Dir.createFileAbsolute(io, path, .{}); defer file.close(io); try file.writeStreamingAll(io, data); } ```