about things

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:

// 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:

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:

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():

// 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:

// 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:

// 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):

// 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:

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:

// 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.Addressnet.IpAddress:

// 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():

// 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:

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);
}