7 ms·
I've been programming in Zig recently and I must say, that's the best error handling I've ever used in any programming language. They are just error return type
by lukaslalinsky 2y ago
I've been programming in Zig recently and I must say, that's the best error handling I've ever used in any programming language. They are just error return type, much like in Go or Rust, but the integration into the language makes it so seamless. It feels like using exceptions, but without the mental and computing overhead coming from the fact that anything can raise an exception.
- lbhdc 2y agoThat has been my experience with zig too, it sparks a lot of joy.
- dataflow 2y ago> They are just error return type https://wg21.link/p2544#expected https://wg21.link/p2544#expected >> the overhead is so high that std::expected is not a good general purpose replacement for traditional exceptions. I'm guessing you don't care about performance that much.
- feznyng 2y agoYou might be right, but it doesn't seem correct to extrapolate that Zig's error return type is slow just because C++'s is. If Zig was designed with this kind of error handling from the start, it may well have optimized for it.
- dataflow 2y ago> You might be right, but it doesn't seem correct to extrapolate that Zig's error return type is slow just because C++'s is. If Zig was designed with this kind of error handling from the start, it may well have optimized for it. It seems pretty correct to me? It's just based on first principles. Returning a value + error is strictly more work than returning just a value, and compilers can't solve the halting problem to optimize away arbitrary amounts of extra work. Ergo, performance hit.
- MobiusHorizons 2y agoComparing zig error handling to no error handling is a bit disingenuous. Error handling does work and therefore costs something. This whole thread is about how exceptions are very expensive when thrown. The question then becomes how different error handling strategies handle real workloads (which will include some percentage of error cases)
- dataflow 2y ago> Comparing zig error handling to no error handling is a bit disingenuous. I'm comparing in-band to out-of-band error signaling, not "error handling to no error handling".
- kllrnohj 2y agoYou can't really "optimize" that every function call now has a branch after it to check for an error. That's a design choice Zig made at the cost of performance, which is not inherently bad. After all, lots of languages intentionally sacrifice performance for some other benefit. But those types of choices are not things you can just waive a magic wand at later to hope it goes away.
- lukaslalinsky 2y agoI stand corrected then, I didn't realize exceptions are this cheap. That's good to know.
- justinpombrio 2y agoHow do you deal with putting information in your error messages? My understanding is that Zig errors can't contain any data. But an error message like "file not found" is awful. Are your error messages awful, or is there some way to get information into them so that you can say "file 'foo/bar.json' not found"?
- lukaslalinsky 2y agoI personally replace it with logging. In most other languages, the common thing is to log error message up in the stack, where you actually handle the error in some way. In Zig, I do it whenever I trigger an error. I've only used Zig for one server application, so having a lot of error messages in logs works fine, even if some of them are possible redundant.
- mlunar 2y agoIn Go you can do errorf("%w: %s", err, path) so that you get "file not found: foo/bar.json", while still being able to match on the wrapped error value with errors.Is(). The caller can do the same with this error and so on up the stack
- fpoling 2y agoI dislike this style in Go. It adds a lot of noise to the source and essentially builds a stack trace manually. In Go 1.23 there is errors.Wrap() that adds the error stack automatically so maybe at some point Go will consider again adding some sugar for automatic error propagation.
- lukax 2y agoGo errors in standard library does not support stack traces. errors.Wrap() only exists in github.com/pkg/errors package
- fpoling 2y agoZig runtime optionally records few last points in sources where the error is propagated to the caller so you get stack traces. If you need more than that and error codes, then either log as the sibling suggested or use custom return types. Anything more complex than what can be encoded as error codes is not an exception.
- cardanome 2y agoGolang arguably has exceptions via panic/recover: https://mitranim.com/posts/goex https://mitranim.com/posts/goex I think the issue is that many languages lacked support for option types for a long time so exceptions got overused and abused. Now the pendulum has swung towards "exceptions are bad". I think both ways of handling errors serve different use cases and it is good to have proper language support for both. I like to use exceptions for errors that are... literally exceptions. Stuff that is out of my control, being out of memory, stuff that I don't expect to happen on the happy path. When the default should be to just log the thing and crash. And if your language supports proper exceptions you get nice stack traces in your logs to see what went wrong. On the other hand error types are superior for things that you should explicitly handle in your code. That are reasonable invariants to take care of. Here the language forcing you to handle them or to explicitly opt out of handling them is extremely valuable. Having more tools is not always bad.