You likely want to pay as much attention as required to make things work, but the purpose of your code isn't to generate errors -- errors are what get in the way of the actual purpose of your code.
For people who want to get an overview of what some code does, the error code is interesting only after you understand the actual purpose, and sprinkling the error code throughout the code that describe the purpose of the program causes distraction.
There's element of personal preference here.
The longer I program the more I favor systems and styles that minimize unexpected problems; explicit error handling is very much in that vein.
Another complication is that the word "error" actually encompasses two very different kinds of situations:
(1) expected-but-non optimal external conditions (there's no file at that path, the tcp connection got closed) and (2) unexpected conditions caused by a bug (array index out of bounds, the regular expression typed into the code is invalid).
Handling (1) gracefully is very much part of the actual purpose of your code: files WILL be missing sometimes, network connections WILL die, so it behooves you and your program to think about these situations as first class.
(2) is not part of the purpose of your program, it's an error IN your program. These are best handled by crashing/exceptions/panic.
A lot of languages mix the handling of (1) and (2), e.g. Python and some styles of C++, which use exceptions for everything. Go uses explicit error returns for (1) and panics for (2), which feels right to me.
This seems like a response to something that wasn't my comment. I even went out of my way to state what I thought might be obvious: "pay as much attention as required to make things work".
Handling errors is a given in this thread. The question was how to represent that in the structure of the program.
> There's element of personal preference here.
I agree that there's some of that, but if you accept that the main purpose of programming language syntax is to ease reading, writing, and understanding programs, then preference only matters to the extent you can know it, and most of us can assume that we do not know the preferences of the people reading and trying to understand our code. Given that, we must try to use somewhat more objective measures.
When reading code, is it more useful to get a broad overview of the algorithm, or more useful to dive into every possible branch? The answer to this won't always be the same, but for a given type of code it will likely lean heavily toward either breadth-first or toward depth-first readings, which correspond fairly closely to whether error handling is done locally at the site of the error. Further, I think most programs will benefit more from a breadth-first organization, such that errors are better handled (syntactically) in a way that doesn't interrupt the process of understanding what the code is supposed to do.
Go has a lot of things I like, but the difficulty of laying out a clear "do this, then this, then this, then that" is not one. Either you end up with "do this (or handle the error from trying to do that by doing this other thing), then this (unless there's an error here, in which case...)", or you abuse panic, or explicitly ignore errors. If you're in this situation, then the first is the best of a bad lot, but unless you're doing some very finicky, low-level code, it would be nicer to be able to handle errors outside of the purposeful flow of the application.
I agree that having a distinction between different kinds of errors is nice, but errors of type (1) are not the purpose of your code. They're problems that prevent your code from fulfilling its purpose. That's a whole different conversation, though. :/
I don't really agree with that. In a module that checks whether a user has the right credentials to perform a given task, for instance by checking the used IP is correct and a correct password is given within 3 attempts (or else the account is blocked), dealing with errors (checking password is valid, checking IP is valid, checking account is not blocked, blocking it if needed) is the purpose of the module.
This is the same with any kind of automaton. Knowing when you go into an error state and how you get out of it is part of the problem you deal with.