> You've made error values. This is just one trivial thing you can do with error values without adding keywords. As you said, it's just a function call.

Well, yeah, with some "ergonomics." Like walking a stack of error handlers. Across threads. Go back and read my code; that's what it's doing: a stack walk across threads, followed by a jump backwards depending on certain conditions.

Does Zig do that? Not builtin, for sure.

Could you implement that in Zig? Sure, but then you're outside its "best-in-class" error system.

> This is the error system that languages like zig and rust have.

So you're admitting that Zig does not have any better error handling than C? Because C has return values.

At least Rust lets you use Option values and Result values.

> Ie. the best paradigm for error handling you can get without all thenoverheadnof a pure FP language.

Sigh...I just implemented something from a functional programming language in C. Overhead is minimal.

> Except Zig has a bunch of erganomic enhancements to make them far more pleasant to deal with and reduce the mental overhead and scope for mistakes. You can't get the value out of a failable function without acknowledging and passing up or handling the error, and you don't need the verbiage of if err != nil adding noise everywhere.

That's just manual exceptions with the compiler complaining if you get it wrong. I mean, sure, it's great that the compiler will check your work, but Clang and GCC can give me warnings about unused return values, so...that's not much better than C.

And they are still exceptions. You're still destroying stack frames until some function higher in the stack handles the error. When it does, all of that context is gone.

Using conditions and restarts means that you can make the decision to tear down the context after* handling the error. Exceptions are much less worse in that case. I've actually found them to be useful in certain cases, but only if the error is handled first.

Also, you can add those ergonomics in C. Like so:

#define try(var, expr) do { typeof(var) ret_ = (expr); if (is_err(ret_)) return ret_; var = ret_; } while (0)

> And it comes with batteries included so you're not going to use code that uses something stupid like errno instead without noticing. And you get errdefer to mitigate one of the biggest downsides to saying 'I can't handle this here, passing an error up'.

I will say that errdefer is a good idea. I did implement basically that.

But no, Zig's error system doesn't come with batteries included because it can't carry arbitrary data. And it doesn't do a walk of a stack of registered handlers. And it doesn't do restarts. And it doesn't have Option or Result, nor interfaces so you could implement the same thing for other types.

Whatever you might think of conditions and restarts, if you seriously think that Zig's error system is best-in-class when Rust's does the same thing and more, while also allowing user code and types to use the same infrastructure, I just don't know what to tell you.

And I'm no fan of Rust. But it's better than Zig.

> They can't carry arbitrary data, because where would you put it in a language that has an error system capable of treating allocation failure as a handleable error?

Preallocate on thread startup. This is not hard.

And on allocation error, every function that allocates is controlled by the language (through the standard library), so that's not a problem in practice. And even if something tries to wrap an allocation failure in more data, and allocation fails again, just panic(). Really. You can even document that behavior in the language.

> There's nothing stopping you from putting some state or context elsewhere, but you have to make those decisions.

Yes, but that's an admission that Zig's error system is not ergonomic. Yet you claim that it is best-in-class simply because it's slightly more ergonomic than C's?

Sigh...