In Zig you need an allocator to allocate anything, so whenever you need to add some extra information to an error, you pass a diagnostics object as an output argument to a potentially failing function. In this case it becomes a bit harder to compare it to Go's errors, each with pros and cons. I think comparing Go errors to Rust errors would be more fair.
There are some articles about the diagnostic pattern in Zig, e.g. [1], [2]
The Go team has discussed syntactic sugar for error handling many times. They're not against it, they're just holding out for a proposal that checks a lot of boxes and makes everyone happy, which hasn't happened yet.
My takeaway is that Go almost always prefers simplicity and not so much good software engineering. `nil` without compiler checks is another example, or designing a new language without generics. However the overall simplicity has its own value.
I agree, its strength (beyond goroutines) is that anyone who knows one of the popular languages (Python, Java, etc) can easily translate their idioms and data structures to Go, and the code would remain easy to read even without much Go experience. That's probably one reason why the TypeScript compiler team chose Go.
But this makes the language feel like Python, in some ways. Besides nil, the lack of expressivity in its expressions makes it more idiomatic to write things imperatively with for loops and appending to slices instead of mapping over the slice. Its structurally typed interfaces feel more like an explicit form of duck typing.
> he popular languages (Python, Java, etc) can easily translate their idioms and data structures to Go, and the code would remain easy to read even without much Go experience
disagree, they made many decisions which are different from mainstream: OOP, syntax as examples.
Sure, the syntax is unique, but it's fairly easy to get over that. I guess I'm comparing to Rust, where not only is syntax different, but data structures like a tree with parent references aren't as straightforward (nor idiomatic), and there's a lot more explicit methods that requires knowing which are important and which are just noise (e.g. unwrap, as_ref).
I would argue that after a short tutorial on basic syntax, it's easier for a Python/JavaScript programmer to understand Go code than Rust.
I think of it as a bit like Python with stronger types.
I'm not convinced that you couldn't have good software engineering support and simplicity in the same language. But for a variety of mostly non-technical reasons, no mainstream language provides that combination, forcing developers to make the tradeoff that they perceive as suiting them best.
The author doesn't touch on it, but the bigger problem with things like Foo|Bar as an actual type (rather than as a type constraint) is that every type must have a default/zero value in Go. This has proven to be a difficult problem for all of the proposals around adding sum types, whether they're used as errors or otherwise. For example, to support interface{Foo|Bar} as a reified type, you'd have to tolerate the nil case, which means you either couldn't call any methods even if they're common to Foo and Bar, or else the compiler would have to synthesize some implementation for the nil case, which would probably have to just panic anyway. And an exhaustive type-switch would always have to have "case nil:" (or "default:") and so on.
Hot take, maybe, but this is one of the few "mistakes" I see with Go. It makes adding QoL things like you mentioned difficult, requires shoehorning pointers to allow for an unset condition, some types don't have a safe default/zero value like maps, and makes comparisons (especially generic) overly complex.
Go specifically does not want to add QoL things because it means the compiler team has to spend time implementing that extra syntax and semantics versus making a minimal set of features better.
Go got a ton right. Especially for being almost 20 years old. But errors is one thing that needs a v2. I love Zig's enumerable errors and deferErr function.
It's more complicated. There is no single correct way to check for errors. Some standard library functions can return data and an error: https://pkg.go.dev/io#Reader
This is true, but it feels like a mistake. It's too late to change now, of course, but I feel like (0, nil) and (!=0, !=nil) should both have been forbidden. The former is "discouraged" now, at least. It does simplify implementations to allow these cases, but it complicates consumers of the interface, and there are far more of the latter than the former.
"Here's the uncomfortable truth: a try keyword in Go without fixing the error type is just syntax sugar. You'd get slightly less typing but none of the real benefits - no exhaustiveness checking, no compiler-inferred error sets, no guarantee that you've actually handled every case."
... So what? From what I can tell that's all anyone has asked for in the context of something to just return nil/error up the call stack.
Exactly. I don't like that many people say "It's not perfect so it's useless.". I don't want to write or read the `if err != nil` statement over and over again. It is messy. It is tiresome. It could be solved by syntactic sugar.
How utterly arrogant to insist that “every Go developer” wishes the language abandoned its principles in order to add some syntactic sugar to save a few lines of code. No, we don’t all feel a pang of envy at magic keywords that only work in certain function call configurations. Sheesh.
I really hate it when people try to justify Go’s design decisions. Try would be very useful. The real reason why is because the Go team refuses to take any lesson from any other programming language except for C. That’s why there are so many questionable decision. Also I was a little disappointed there was no mention of panics which are one such questionable decision. Also the author stopped trying to cover up their AI written tracks at the conclusion because you already read it so who cares.
In Zig you need an allocator to allocate anything, so whenever you need to add some extra information to an error, you pass a diagnostics object as an output argument to a potentially failing function. In this case it becomes a bit harder to compare it to Go's errors, each with pros and cons. I think comparing Go errors to Rust errors would be more fair.
There are some articles about the diagnostic pattern in Zig, e.g. [1], [2]
[1] https://github.com/ziglang/zig/issues/2647#issuecomment-5898...
[2] https://mikemikeb.com/blog/zig_error_payloads/
The programmer is explicitly throwing away the error returned by ReadFile (using the underscore) in the criticism of Go.
Saying that is not explicit is just wrong.The Go team has discussed syntactic sugar for error handling many times. They're not against it, they're just holding out for a proposal that checks a lot of boxes and makes everyone happy, which hasn't happened yet.
Example: https://go.dev/blog/error-syntax
It's a settled matter at this point for the foreseeable future
https://go.dev/blog/error-syntax
tl;dr - proposals are no longer being considered
My takeaway is that Go almost always prefers simplicity and not so much good software engineering. `nil` without compiler checks is another example, or designing a new language without generics. However the overall simplicity has its own value.
I agree, its strength (beyond goroutines) is that anyone who knows one of the popular languages (Python, Java, etc) can easily translate their idioms and data structures to Go, and the code would remain easy to read even without much Go experience. That's probably one reason why the TypeScript compiler team chose Go.
But this makes the language feel like Python, in some ways. Besides nil, the lack of expressivity in its expressions makes it more idiomatic to write things imperatively with for loops and appending to slices instead of mapping over the slice. Its structurally typed interfaces feel more like an explicit form of duck typing.
Also, Go has generics now, finally.
> he popular languages (Python, Java, etc) can easily translate their idioms and data structures to Go, and the code would remain easy to read even without much Go experience
disagree, they made many decisions which are different from mainstream: OOP, syntax as examples.
Sure, the syntax is unique, but it's fairly easy to get over that. I guess I'm comparing to Rust, where not only is syntax different, but data structures like a tree with parent references aren't as straightforward (nor idiomatic), and there's a lot more explicit methods that requires knowing which are important and which are just noise (e.g. unwrap, as_ref).
I would argue that after a short tutorial on basic syntax, it's easier for a Python/JavaScript programmer to understand Go code than Rust.
I think of it as a bit like Python with stronger types.
I'm not convinced that you couldn't have good software engineering support and simplicity in the same language. But for a variety of mostly non-technical reasons, no mainstream language provides that combination, forcing developers to make the tradeoff that they perceive as suiting them best.
The author doesn't touch on it, but the bigger problem with things like Foo|Bar as an actual type (rather than as a type constraint) is that every type must have a default/zero value in Go. This has proven to be a difficult problem for all of the proposals around adding sum types, whether they're used as errors or otherwise. For example, to support interface{Foo|Bar} as a reified type, you'd have to tolerate the nil case, which means you either couldn't call any methods even if they're common to Foo and Bar, or else the compiler would have to synthesize some implementation for the nil case, which would probably have to just panic anyway. And an exhaustive type-switch would always have to have "case nil:" (or "default:") and so on.
> every type must have a default/zero value in Go
Hot take, maybe, but this is one of the few "mistakes" I see with Go. It makes adding QoL things like you mentioned difficult, requires shoehorning pointers to allow for an unset condition, some types don't have a safe default/zero value like maps, and makes comparisons (especially generic) overly complex.
Go specifically does not want to add QoL things because it means the compiler team has to spend time implementing that extra syntax and semantics versus making a minimal set of features better.
Go got a ton right. Especially for being almost 20 years old. But errors is one thing that needs a v2. I love Zig's enumerable errors and deferErr function.
It's more complicated. There is no single correct way to check for errors. Some standard library functions can return data and an error: https://pkg.go.dev/io#Reader
This is true, but it feels like a mistake. It's too late to change now, of course, but I feel like (0, nil) and (!=0, !=nil) should both have been forbidden. The former is "discouraged" now, at least. It does simplify implementations to allow these cases, but it complicates consumers of the interface, and there are far more of the latter than the former.
"Here's the uncomfortable truth: a try keyword in Go without fixing the error type is just syntax sugar. You'd get slightly less typing but none of the real benefits - no exhaustiveness checking, no compiler-inferred error sets, no guarantee that you've actually handled every case."
... So what? From what I can tell that's all anyone has asked for in the context of something to just return nil/error up the call stack.
Exactly. I don't like that many people say "It's not perfect so it's useless.". I don't want to write or read the `if err != nil` statement over and over again. It is messy. It is tiresome. It could be solved by syntactic sugar.
llm garbage
The llm detector in my brain went off too
agreed, the author should be upfront that it was written by an LLM
How utterly arrogant to insist that “every Go developer” wishes the language abandoned its principles in order to add some syntactic sugar to save a few lines of code. No, we don’t all feel a pang of envy at magic keywords that only work in certain function call configurations. Sheesh.
I really hate it when people try to justify Go’s design decisions. Try would be very useful. The real reason why is because the Go team refuses to take any lesson from any other programming language except for C. That’s why there are so many questionable decision. Also I was a little disappointed there was no mention of panics which are one such questionable decision. Also the author stopped trying to cover up their AI written tracks at the conclusion because you already read it so who cares.