Idiomatically, go uses errors for the purposes other languages use exceptions, so if this makes debugging harder, it's an important consideration.
However, the question was asking what is different about errors compared to other values. The add function above contains an error, yet I don't know of any language in existence where you would expect a stack trace bundled alongside the result to help you debug it. Why would that need change just because you decided to return a struct instead of an int? And actually, many APIs in the wild do represent errors as integers.
Python does. Ruby does. It's not just Java and JS. Go is very open about its approach being a departure.
> And actually, many APIs in the wild do represent errors as integers.
Many, many APIs in the wild are implemented in (or meant to be consumed from) C, which doesn't even have exceptions, so not using exceptions makes sense for them.
Very often idiomatic non-C host language wrappers for those APIs will fire exceptions when they get an error return.
And it's awful. I use EAFP locally (to avoid TOCTOU and the like) at low level interfaces but I don't let it bubble up out of a function scope, because it is a goto in all but name.
I've also been increasingly using the `result` library/data structure. It's incredibly liberating to return an error as an object you can compose into other functions, vs try/catch, which does not compose.
Yes I write python almost like rust, and it's great. Strong types, interfaces, immutable types. It looks nothing like "old school python" but also behaves nothing like it. Gone are the day of "oh it crashed again, fix one line and rerun".
Exceptions should be for exceptional circumstances, not errors.
Edit: I see this is controversial. What do you take objection to? Making your python look less dynamic and more like rust? Try it before you knock it. Python's my favorite language, but I do not agree that many of the common "pythonic" patterns are good at scale.
Definitely not. Especially because early Ruby implementations brought huge overhead when exceptions were used, you were strongly advised to only use exceptions for actual exceptions. Ruby was one of the first languages that really started pushing the idea that exceptions should be reserved for exceptions, even if was just for technical reasons.
Those overhead problems have been addressed and are no longer a problem, but the sentiment has continued to ring true. I agree that doesn't stop people from trying to overload them, as I said earlier. But idiomatic? Not at all.