Going on a tangent, but lately I have been of the sentiment that the capture-less catch in Zig is a footgun. It’s way too easy to just plonk it after a function call and be done with it without properly considering and/or handling all the possible error values. The fixes in your second PR seem to support this view.
Honestly, I’ve come to the conclusion that I’d either like it to be outright removed from the language, or at least restricted to cases where there is only a single possible error value, with only an explicit catch |e| allowed in all other cases. I believe this might push programmers to handle each and every error case, or at least to think about them harder.
For a potentially even more controversial idea, I’ve been thinking whether catch should perhaps be redesigned completely, becoming its own switch-like construct. Think something like this:
fallibleFunc() catch {
error.Canceled => return error.Canceled,
error.SomeOtherFailure => {
// handle SomeOtherFailure here
},
else => |e| {
// we can still use `else` to handle the rest
},
};
This way, you could still get a catch-all, but you’d be forced to think slightly harder about it because you’d have to write this beautiful[1] thing:
fallibleFunc() catch {
else => {
// some handler code
},
};
No other forms of catch would be allowed, except maybe a shorthand when there is only a single value in the error set. Although I can immediately tell that just a catch <expression> would cause ambiguity in the syntax, so it would probably have to be something else. Maybe allow orelse for single-error sets?
In any case, there’d still be try when we don’t want to think about it at certain points in the code.
Summarized: since errors are meant to be a control flow mechanism, it might do us some good to be pushed towards that ideal some more.
/s ↩︎