🎓 A1Learner
🔍
0 of 55 lessons completed

Zig Error Sets

An error set is a named group of errors that a function can report. Writing the group down tells every caller exactly which failures to expect.

An error set names its errors

The set lists each error the code can report. The print shows the name of one member.

const std = @import("std");

const MathError = error{ DivideByZero, Negative };

pub fn main() !void {
    const out = std.io.getStdOut().writer();
    const e: MathError = error.DivideByZero;
    try out.print("{s}\n", .{@errorName(e)});
}

An error union can hold a value

divide returns MathError!i32, so it can give back a number. This call succeeds and the number prints.

const std = @import("std");

const MathError = error{ DivideByZero, Negative };

fn divide(a: i32, b: i32) MathError!i32 {
    if (b == 0) {
        return error.DivideByZero;
    }
    return @divTrunc(a, b);
}

pub fn main() !void {
    const out = std.io.getStdOut().writer();
    const answer = try divide(20, 4);
    try out.print("{d}\n", .{answer});
}

Each member of the set stays distinct

A switch reads one error value from the set. Each member leads to its own word.

const std = @import("std");

const MathError = error{ DivideByZero, Negative };

pub fn main() !void {
    const out = std.io.getStdOut().writer();
    const e: MathError = error.Negative;
    const word = switch (e) {
        error.DivideByZero => "zero",
        error.Negative => "negative",
    };
    try out.print("{s}\n", .{word});
}

Example

const std = @import("std");

const MathError = error{ DivideByZero, Negative };

fn divide(a: i32, b: i32) MathError!i32 {
    if (b == 0) {
        return error.DivideByZero;
    }
    return @divTrunc(a, b);
}

fn doublePositive(n: i32) MathError!i32 {
    if (n < 0) {
        return error.Negative;
    }
    return n * 2;
}

pub fn main() !void {
    const out = std.io.getStdOut().writer();
    const answer = try divide(42, 6);
    const doubled = try doublePositive(9);
    try out.print("{d}\n", .{answer});
    try out.print("{d}\n", .{doubled});
    try out.print("{s}\n", .{@errorName(error.Negative)});
}

Key points

  • Error set: a named list of errors written as error{ A, B }.
  • Declaration: const MathError = error{ DivideByZero, Negative }; defines a set with two members.
  • Error value: error.DivideByZero is one member of a set, ready to return or store.
  • Error union: MathError!i32 is a type that holds an i32 value or one error from the set.
  • Return: a function gives back a value on success and returns an error when the work fails.
  • Name check: @errorName(err) gives the bare name of an error, such as DivideByZero.

In this example, divide and doublePositive both return MathError!i32, so each one can give back a number or one error from the set. Both calls succeed, so try unwraps 7 and 18. The last line prints the name of the Negative member with @errorName.

Note

an optional marks a missing value with null, while an error set names the reason it is missing.

Try it Yourself

Edit the code, then press Run.

Running is simulated

Exercise

Which line defines an error set with two errors named Low and High?