Skip to content

Instantly share code, notes, and snippets.

@roninjin10
Last active April 28, 2026 19:53
Show Gist options
  • Select an option

  • Save roninjin10/5ab4270b9d9b004e014fca27985b9acf to your computer and use it in GitHub Desktop.

Select an option

Save roninjin10/5ab4270b9d9b004e014fca27985b9acf to your computer and use it in GitHub Desktop.
Zig 0.16.0

Zig 0.15.x

Language / type system

  • usingnamespace keyword removed entirely; refactor to explicit imports / conditional expressions (the mixin pattern now uses zero-bit fields plus @fieldParentPtr("name", m)).
  • async and await keywords removed; @frameSize builtin removed. To be replaced by stdlib I/O-based implementations.
  • Packed union fields no longer accept align attributes (matches packed structs).
  • New rules for undefined: only operators that cannot trigger illegal behavior accept undefined operands; arithmetic on undefined is now a compile error / illegal behavior.
  • Integer-to-float coercion is a compile error at comptime when precision would be lost; integer literals must be written as float literals (e.g. 123_456_789 → 123_456_789.0).
  • Inline assembly clobber lists changed from string syntax to typed struct syntax (zig fmt auto-upgrades).
  • @ptrCast extended to allow single-item-pointer → slice (slice byte count matches operand).
  • Boolean vector operators (!, &, |, ^, and/or semantics) now defined on bool vectors.

Standard library

  • "Writergate" — std.io reader/writer interfaces overhauled into std.Io:
    • std.io.GenericReader / std.io.AnyReader → std.Io.Reader
    • std.io.GenericWriter / std.io.AnyWriter → std.Io.Writer
    • std.io.SeekableStream removed; use concrete std.fs.File.Reader / std.fs.File.Writer.
    • std.io.BitReader, std.io.BitWriter removed.
    • std.Io.LimitedReader, std.Io.BufferedReader removed.
    • std.io.CountingWriter removed; use std.Io.Writer.Discarding or std.Io.Writer.Allocating.
    • std.io.BufferedWriter removed; pass an explicit buffer to a file writer.
    • std.fifo module removed entirely (std.fifo.LinearFifo gone).
    • std.RingBuffer removed (replaced by I/O stream ring buffers).
    • std.fs.File.reader() / .writer() → .deprecatedReader() / .deprecatedWriter(); new .reader(buffer) / .writer(buffer) require a caller-provided buffer and explicit flush().
    • std.fs.File.WriteFileOptions, std.fs.File.writeFileAll, std.fs.File.writeFileAllUnseekable removed.
    • std.fs.Dir.atomicFile now requires write_buffer in options; fs.AtomicFile.File field replaced with File.Writer.
    • std.posix.sendfile removed in favor of std.fs.File.Reader.sendFile.
    • std.fs.Dir.copyFile no longer returns error.OutOfMemory.
  • Formatting overhaul:
    • format method signature changed from fn format(self, comptime fmt: []const u8, options: std.fmt.FormatOptions, writer: anytype) !void to fn format(self, writer: *std.Io.Writer) std.Io.Writer.Error!void.
    • {} no longer calls a type's format method; you must use {f}.
    • std.fmt.FormatOptions removed; alignment over Unicode codepoints removed (ASCII/bytes only).
    • std.fmt.format → std.Io.Writer.print.
    • std.fmt.Formatter → std.fmt.Alt (requires explicit context type).
    • std.fmt.fmtSliceHexLower / fmtSliceHexUpper removed → use {x} / {X}.
    • std.fmt.fmtSliceEscapeLower / fmtSliceEscapeUpper → std.ascii.hexEscape.
    • std.fmt.fmtIntSizeDec / fmtIntSizeBin removed → use {B} / {Bi}.
    • std.fmt.fmtDuration / fmtDurationSigned removed → use {D}.
    • std.zig.fmtEscapes → std.zig.fmtString.
    • New specifiers: {t} (tag name), {b64} (base64).
  • Collections — ArrayList and friends migrated to unmanaged-by-default:
    • std.ArrayList(T) (managed) → std.array_list.Managed(T); the unmanaged variant is now the default std.ArrayList.
    • std.ArrayListAligned → std.array_list.AlignedManaged.
    • std.BoundedArray removed; use ArrayListUnmanaged with a fixed buffer.
    • std.DoublyLinkedList(T) de-genericified: nodes are now std.DoublyLinkedList.Node embedded in user structs and traversed with @fieldParentPtr.
    • std.compress.flate.CircularBuffer removed.
  • Compression: std.compress.flate.Decompress now takes a container parameter; higher-level compression and checksum helpers removed (do checksums out-of-band, use third-party packages for compression).

Build system / toolchain

  • Deprecated implicit root-module fields on std.Build.ExecutableOptions (and siblings) removed, including root_source_file; must use the root_module field introduced in 0.14.0.
  • std.Build.Step.Compile.sanitize_c changed type from ?bool to ?std.zig.SanitizeC; replace true/false with .full/.off.
  • -fsanitize-c split into -fsanitize-c=full and -fsanitize-c=trap.
  • x86_64 self-hosted backend is now the default for Debug mode (except NetBSD, OpenBSD, Windows, which still default to LLVM).
  • New CLI: zig test-obj (compile tests to an object file instead of an executable).
  • LLVM bumped to 20.1.8.
  • zig cc: -static and -dynamic now respected.
  • zig objcopy regressed; some subcommands now return "unimplemented".

Sources:

  • 0.15.1 Release Notes

Zig 0.16.0

Language / type system

  • @Type builtin removed. Replaced by @Int, @Tuple, @Pointer, @Fn, @Struct, @Union, @Enum, @EnumLiteral.
  • @cImport deprecated. Use the build system: b.addTranslateC(...).
  • @intFromFloat deprecated. @floor, @ceil, @round, @trunc now convert directly to integer types.
  • Unary float builtins (@sqrt, @sin, @floor, …) forward result types into earlier operations.
  • Integer → float coercion is implicit when all values fit losslessly.
  • Runtime indexing of vectors with non-comptime values is forbidden — coerce to array first.
  • Array ↔ vector in-memory coercion removed.
  • Returning the address of a local variable is now a compile error (returning address of expired local variable).
  • *u8 and *align(1) u8 are now distinct types (they coerce, but are not identical).
  • Pointers to comptime-only types (e.g. *comptime_int) are no longer themselves comptime-only.
  • Packed structs/unions:
    • Switch on packed types compares solely on the backing integer.
    • All packed-union fields must have identical @bitSizeOf matching a backing integer.
    • Pointers are forbidden as fields of packed structs/unions.
    • Packed unions accept explicit backing-integer syntax: packed union(u16) { … }.
    • Packed structs/unions with inferred backing integer, and enums with inferred tag types, are no longer valid extern types.
  • Lazy field analysis: structs/unions/enums/opaques only resolve when size or field types are required — affects code that probed types via @typeInfo.
  • Zero-bit tuple fields no longer auto-promote to comptime fields.
  • New dependency-loop cases; error messages explain the loop.

std.Io — the big one

Anything that "potentially blocks control flow or introduces nondeterminism" now lives behind a std.Io instance.

  • File system fully migrated std.fsstd.Io.Dir / std.Io.File:
    • fs.Dirstd.Io.Dir
    • fs.Filestd.Io.File
    • fs.File.Modestd.Io.File.Permissions
    • fs.cwdstd.Io.Dir.cwd
    • fs.realpathstd.Io.Dir.realPathFileAbsolute
    • fs.Dir.makeDirstd.Io.Dir.createDir
    • fs.Dir.makePathstd.Io.Dir.createDirPath
    • fs.Dir.makeOpenDirstd.Io.Dir.createDirPathOpen
    • fs.Dir.rename now takes two Dir parameters; returns error.DirNotEmpty instead of error.PathAlreadyExists.
    • fs.Dir.chmodstd.Io.Dir.setPermissions
    • fs.Dir.chownstd.Io.Dir.setOwner
    • fs.File.setEndPosstd.Io.File.setLength
    • fs.File.getEndPosstd.Io.File.length
    • fs.File.readstd.Io.File.readStreaming
    • fs.File.writestd.Io.File.writeStreaming
    • fs.File.updateTimesstd.Io.File.setTimestamps
    • All *Z and *W path variants removed (realpathZ, realpathW, makeDirAbsoluteZ, deleteDirAbsoluteZ, deleteTreeAbsolute, etc. — ~300 functions deleted).
  • Time:
    • std.time.Instantstd.Io.Timestamp
    • std.time.Timerstd.Io.Timestamp
    • std.time.timestamp()std.Io.Timestamp.now(io)
  • Randomness:
    • std.crypto.random.bytesio.random
    • std.crypto.randomstd.Random.IoSource via io.interface()
    • posix.getrandomio.random
  • Synchronisation primitives all relocated under std.Io:
    • std.Thread.Mutexstd.Io.Mutex
    • std.Thread.Conditionstd.Io.Condition
    • std.Thread.RwLockstd.Io.RwLock
    • std.Thread.Semaphorestd.Io.Semaphore
    • std.Thread.WaitGroupstd.Io.Group
    • std.Thread.ResetEventstd.Io.Event
    • std.Thread.Futexstd.Io.Futex
    • std.Thread.Pool removed.
    • std.Thread.Mutex.Recursive removed.
    • std.once removed.
    • heap.ThreadSafeAllocator removed.
  • Process:
    • std.process.Child.initstd.process.spawn(...) with options struct.
    • std.process.execvstd.process.replace.

Standard library — non-Io changes

  • fmt.Formatterfmt.Alt.
  • fmt.formatstd.Io.Writer.print.
  • fmt.bufPrintZfmt.bufPrintSentinel.
  • Removed: SegmentedList, meta.declList, Io.GenericWriter, Io.AnyWriter, Io.null_writer, Io.CountingReader.
  • Error renames:
    • error.RenameAcrossMountPointserror.CrossDevice
    • error.NotSameFileSystemerror.CrossDevice
    • error.SharingViolationerror.FileBusy
    • error.EnvironmentVariableNotFounderror.EnvironmentVariableMissing
  • Debug:
    • captureStackTracecaptureCurrentStackTrace
    • dumpStackTraceFromBasedumpCurrentStackTrace
    • writeStackTraceWindowswriteCurrentStackTrace
    • std.debug.StackIterator no longer pub.
  • BitSet / EnumSet initEmpty/initFull replaced with declaration literals.
  • Container migration to "unmanaged" forms continues across the std lib.
  • DynLib: Windows support removed (LoadLibraryExW + GetProcAddress directly).
  • std.posix almost entirely removed; OS-specific APIs gone.

Build system / toolchain

  • Local package overrides in the build system.
  • Project-local package fetching (instead of global cache).
  • Unit-test timeouts.
  • New --error-style and --multiline-errors flags.
  • LLVM 21; loop vectorisation disabled to dodge a regression.
  • Solaris / AIX / z/OS removed; illumos still supported.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment