I think the key difference is between assertions/"this should never happen" error checking, and actual error conditions that you want to pass back to client code, because it knows better than you do what the right thing to do is.
When you're writing reusable library code (and when you think about the scale of Google's codebase, they must have an insane amount of these libraries), it's important to make this distinction. There are some error conditions where you really just want to say "if this ever happens, just die, because there's nothing sane to be done", and Go provides panic() for these situations, similar to the error() function in your code above.
For situations where you do want to return a meaningful error to the client, I think Go's multiple return values provide a very good way to do it, far better than the overloading of NULL or -1 that you find in C and C++.
The list of cool things Go doesn't have is a darn long one. They opted for simplicity at lots of points. I think it is worth noting these were decisions, not necessarily oversights.
There are a lot of great languages that end up mostly academic because they lack whatever the magical balance of features, simplicity and usefulness it takes for a language get mind share.
I suspect Go might have hit the magical balance with channels, strong types, great build system, simple minimal syntax and language keywords, fairly opinionated best practices (and formatting) and static single file deploys.
Multiple return values are something completely different from sum types. Just because Go by convention returns errors as an additional return values where other languages prefer sum types, you shouldn't conflate the two.
Parent didn't say they were the same, rather they implied that sum types are better.
Sum types can handle multiple return values seamlessly in a typesafe way as a special case, but are not limited to that because they may have different data shapes other than simple products, and callers can be checked to deal with each possible shape at each call site by the compiler.
Claiming sth is "better" requires two things to be comparable, and thus, reasonable similarity in their resp. nature. Claiming something is better than something else implies this similarity (otherwise any comparison would be moot), which I refuted in this particular case.
On a side note, the same people who claim that sum types are "better" are never able to come up with a constructive proposal how sum types could be integrated into Go in an elegant way.
They are "better" in that they are, in fact, more constrained; only when the error case arises will there be any accessible error value; otherwise, the actual expected value will be found. Since go uses an ad hoc product type, you always get an error value and the return value, even if they are mutually exclusive most of the time.
Also, they are both ways to build larger types from smaller ones, and the way they go about doing it is rather obvious from their names, and thus the contrast.
> On a side note, the same people who claim that sum types are "better" are never able to come up with a constructive proposal how sum types could be integrated into Go in an elegant way.
Forgo the cutesy anonymous members for the massive benefits of sum types? For a team which prides itself for its ability to perform trade-offs, they sure were rigid in this stance.
> They are "better" in that they are, in fact, more constrained; only when the error case arises will there be any accessible error value; otherwise, the actual expected value will be found. Since go uses an ad hoc product type, you always get an error value and the return value, even if they are mutually exclusive most of the time.
But multiple return values are there for much more than returned result and error. You conflate that with the specific use of returning result and error, and based on that, you claim that sum types are better. That's a straw man par excellence.
Sum types and multiple return values are not mutually exclusive, though several languages today use tuples to emulate multiple return types (see Scala, Rust for examples).
I am not a language designer, but I have become interested in languages in the past couple of years. Sum types require some sort of generics implementation, which Go does not have. I think the design choices the authors made regarding the language have made adding generics that much harder, that now they are struggling to find the "Go way" of fitting them into the language.
When you're writing reusable library code (and when you think about the scale of Google's codebase, they must have an insane amount of these libraries), it's important to make this distinction. There are some error conditions where you really just want to say "if this ever happens, just die, because there's nothing sane to be done", and Go provides panic() for these situations, similar to the error() function in your code above.
For situations where you do want to return a meaningful error to the client, I think Go's multiple return values provide a very good way to do it, far better than the overloading of NULL or -1 that you find in C and C++.