But there is value in providing a different control flow for errors, which is why exceptions have become prevalent in most programming languages in the past decades.
The value is that your code's happy path is clean and not encumbered with error checks every ten lines, like we see in Go sources all the time.
Separating the happy path and the error handling in different sections of the code contributes to clean code, especially if exceptions are checked and cannot be ignored by the developer.
In my experience, separating the happy path from the error handling leads to unhandled errors. Just yesterday, one of our python projects (an API with about 600 endpoints) started barfing an error for non-parseable JSON because something at the top level caught it. I have no clue where it came from nor how to reproduce it. Had we been handling errors when and where they occur, I would have a vastly shorter debugging period in front of me.
> In my experience, separating the happy path from the error handling leads to unhandled errors.
No, the separation has nothing to do whether errors are handled or not.
If error handling is mandated by the compiler (e.g. checked exceptions), there will be no unhandled errors since the compiler will simply refuse to compile your code until you handle these errors.
Whether you handle these errors near the happy path or in a different section of the code is an orthogonal concern.
Or people will simply elect to use unchecked exceptions, and users will see stack traces frequently. In either case, Go programs don't seem to suffer from bugs in the error handling paths like Java and friends. YMMV.
I don't see the value in a clean happy path and a hidden error path.
It completely invalidates your argument. Your argument is that an error-handling system as described would be undesirable because it would result in developers misusing unchecked exceptions. Go already has unchecked exceptions in the form of `panic`.
So either developers are already abusing it, in which case go's current error-handling approach is no better than the one proposed according to your metric. Or developers have access to it but aren't abusing it, in which case there's no reason to expect they'd abuse it in a system where doing it the right way is even easier than it is today.
In my experience, users already do experience stack traces as it's embarrassingly easy to accidentally operate on a nil pointer.
The value is that your code's happy path is clean and not encumbered with error checks every ten lines, like we see in Go sources all the time.
Separating the happy path and the error handling in different sections of the code contributes to clean code, especially if exceptions are checked and cannot be ignored by the developer.