I think it's a little bit complicated to explain but mostly it boils down to this: errors are real. Java methods kind of let you ignore them through declaring exceptions, with this idea that, well, somebody else will deal with it. Golang functions make errors feel more present. They force you to think about how you're going to handle the errors up front, and to question whether or not you even should error in a particular instance. It's actually helped change the way I think about functions. There are many behaviors that in Java I would not have even considered making them idempotent but in golang making them idempotent is both easier and, as it turns out, more robust.
The patterns for error handling the golang have introduced are admittedly verbose, but they do lend a certain element of confidence that once the code is written, the errors should be handled. Of course a programmer can ignore the errors explicitly but doing so is different than forgetting to catch a thrown exception, because the programmer must go out of their way to write code ignoring the error. It feels like there's more agency around the decision.
The difference is that with exceptions sloppy code is the default.
As you write code in a language with explicit errors, the language makes you acknowledge that the code you call can error out. This makes you stop and think what to do about the error. You can choose to ignore it, but that's a conscious decision that the language forces you to make.
With exceptions, there's no such feedback mechanism from the language/compiler. In order to write robust code you yourself must have the discipline to add exception handlers around the appropriate calls.
In short, defaults matter. It's simply easier to write correct, robust code when you don't have to go out of your way to do it.
> It’s really hard to write good exception-based code since you have to check every single line of code (indeed, every sub-expression) and think about what exceptions it might raise and how your code will react to it.
Only checked exceptions. And the integration of checked exceptions is so bad, and the split between checked and unchecked so arbitrary, that most codebases have sworn off of them.
The patterns for error handling the golang have introduced are admittedly verbose, but they do lend a certain element of confidence that once the code is written, the errors should be handled. Of course a programmer can ignore the errors explicitly but doing so is different than forgetting to catch a thrown exception, because the programmer must go out of their way to write code ignoring the error. It feels like there's more agency around the decision.