> Except that you cannot easily chain calls that return errors, or it isn't really that hard to accidentally ignore errors because of shadowing or overwriting the variable you're storing your errors in. Or the fact that using a union type to represent errors is a strictly superior way, both in terms of usability, as well as correctness. People should just face the fact that returning errors as a product type is a mistake.
These are still essentially the same. Errors are returned as values, with no major difference in runtime semantics. Whether the language supports union types is orthogonal to that.
> You may want to see what approaches Akka or Erlang takes here. golang authors just decided to ignore established practices and use clunky approaches to problems that have already been solved.
There's not one solution, there are multiple solutions with various tradeoffs. The tradeoffs Go made are congruent with its tenets as a language that values simplicity and low cognitive overhead.
> These are still essentially the same. Errors are returned as values, with no major difference in runtime semantics. Whether the language supports union types is orthogonal to that.
It's not just about runtime semantics. If it were, then exceptions should perform better than returned error values in the non-error case (which should be the majority of the time anyway). It's also about how code gets written, and more importantly, how code is read.
> There's not one solution, there are multiple solutions with various tradeoffs. The tradeoffs Go made are congruent with its tenets as a language that values simplicity and low cognitive overhead.
Which in practice, doesn't really show. Simplicity at the language level manifests as longer, more complicated code in real designs, because real life is complicated. It's pushing the load from the language and compiler implementors on to the end user.
They're essentially the same, in a sense that if/goto is essentially the same as a loop. In practice, there's a big pragmatic difference.
And I have to say, the debate around Go error handling does remind me a fair bit of some of the arguments I've read while researching that ancient debate about structured programming - needless abstraction that we're not even sure is right, it's clearer when it's explicit, language is simpler etc.
golang just brought these arguments back, and they're ending up reinventing most of what's been done, but in a subpar way (e.g. code gen instead of generics, verbose error handling + panics instead of exceptions, etc.).
FWIW I don't think panics are a bad idea necessarily, they're just very different from errors. Errors are part of the API contract (whether enforced by the language or not). Panics are for when the contract is broken on either side, or expected invariants suddenly don't hold - the reason being that if your basic guarantees about process state are broken, you can't really guarantee that you'll be able to handle the error either, and trying to do so regardless might result in a security issue.
This distinction is growing popular in general, including languages that have exceptions (e.g. FailFast in C#) and error types (e.g. panic in Rust).
These are still essentially the same. Errors are returned as values, with no major difference in runtime semantics. Whether the language supports union types is orthogonal to that.
> You may want to see what approaches Akka or Erlang takes here. golang authors just decided to ignore established practices and use clunky approaches to problems that have already been solved.
There's not one solution, there are multiple solutions with various tradeoffs. The tradeoffs Go made are congruent with its tenets as a language that values simplicity and low cognitive overhead.