Zig NEWS

Discussion on: Sneaky Error Payloads

Collapse
 
batiati profile image
Rafael Batiati

I wish we had union(error) as a first class citizen in Zig.

Yes, I know, each payload has its requirements for init/deinit and Zig can't magically handle that, I know.

But, it can be solved if the caller is forced to handle a function that returns a union(error) or popup exactly the same type. No inferred errors should be allowed for this use case. This way, the caller is always responsible to clean up any resources a payload uses (e.g call payload.deinit();)

Example:

pub const CustomError = union(error) {
    SimpleError: void,
    ErrorWithPayload: []const u8,
};

pub fn add_one(number: u64) CustomError!u64 {
    if (number == 42) {
        return CustomError { .ErrorWithPayload = "bad number encountered" }; 
    } else {
        return number + 1;
    }
};

//Correct usage
pub fn use_it_handling_the_error() void {
    _ = add_one(42) catch |err| switch(err) {
        .ErrorWithPayload => |payload| std.debug.print("errored with payload: {s}! \n", .{ payload }),
        _ => std.debug.print("errored a simple error!\n", .{ }),
   };
}

//Another correct usage
pub fn use_it_returning_the_same_error() CustomError!void {
    _ = try add_one(42);
}

//Incorrect usage (compiler error)
pub fn use_it_inferring_the_error() !void {
    _ = try add_one(42);
}

Enter fullscreen mode Exit fullscreen mode

PS: Yes, we can do that in user land already, but without being able to use try/catch.

pub const CustomResult = union(enum) {
    Success: u64,
    SimpleError: void,
    ErrorWithPayload: []const u8,
};

pub fn add_one(number: u64) CustomResult {
    if (number == 42) {
        return CustomResult { .ErrorWithPayload = "bad number encountered" }; 
    } else {
        return CustomResult { .Success = number + 1 };
    }
};
Enter fullscreen mode Exit fullscreen mode