PSA: `lhs == error.Typo` is not a compilation error

See this example:

fn foo() error{Fail}!void {
    return error.Fail;
}

pub fn main() void {
    if (foo() == error.Pineapple) {
        // 😱
    }
}

Although foo returns a specific error set, == doesn’t check that the literal on the right is a member of it.

Feels error prone!

Hat tip to The unexpected productivity boost of Rust

6 Likes

But could it be made into a compile error?
It seems like it could be.

2 Likes

error. can refer to any error. If the compiler had never seen that error before, it introduces it at that point. So I don’t think it can be made a compiler error.
Instead, I suggest always defining an error set for all errors you are working with, and rigorously reference your errors through your set:

const FooError = error{Fail};

fn foo() FooError!void {
    return FooError.Fail;
}

pub fn main() void {
    // Now this is a compiler error
    if (foo() == FooError.Pineapple) {
        // 😀
    }
}
5 Likes

It’s news to me that this is a valid way of handling a possible error, so I went back and tried older versions to see if this was always the case.

In the stage1 (C++) compiler, this was an error:

./eql-catch.zig:8:15: error: operator not allowed for type 'error{Fail,Pineapple}!void'
    if (foo() == error.Pineapple) {

So I’d honestly consider this a self-hosted compiler regression, unless it’s truly intentional that an error union can be compared using ==.

1 Like

Nevermind, it was fully intentional:

I don’t quite understand the use-case, though.

However: https://github.com/ziglang/zig/issues/24028

1 Like

Comparing errors with == seems fine, but upcasting a specific error union to anyerror feels like a bug.

3 Likes

yes looking at the proposal issue it doesn’t seem to state that the upcasting is intentionally wanted

Relevant issue:

2 Likes