| So what you mean to say is that the problem is not so much that there isn't any error reporting, but that, in C, it's being ignored ? Never do printf("here's a number: %d", 11);
Always do: int attempts = 0
int ret = printf("here's a number: %d", 11);
while (attempts++ < max_attempts && ret < 0) {
switch (ret) {
case EINTR:
case EAGAIN:
ret = printf("here's a number: %d", 11);
default:
// At this point you, as a programmer, should STOP AND THINK.
// What would be a reasonable reaction here ? How will it affect
// everything else the program does ? What is the correct way to
// proceed ?
//
// P.S. Anyone doing "return -1;" at this point should be taken out and shot.
// and yes, that's the C equivalent of what every Go programmer always does.
panic("printf error", ret); // for example, crash the program.
}
}
Needless to say, you should do this on EVERY printf statement.There. Isn't explicit erroring great ? NO IT ISN'T. Needless to say, this has an almost direct translation to Go. Does anyone do this ? Of course not. In Go, like in C, like in shell scripting, in the vast majority of programs nearly all errors are ignored. That's why exceptions are so very superior to explicit error handling : it accomplishes many things : 1) it alerts the user that an error occured. "Explicit error handling" like C, Go, most C++, ... do will simply silently attempt to proceed, likely turning a small error or a typo into a disaster or catastrophe. Silent database corruption, here we come ! 2) It provides information about where the error occured. Stop me if this sounds familiar: "when an error is printed, and the program crashes, I download the source and grep it for what I think is a unique word in the error message. When it turns out it isn't I get cranky. When it turns out there isn't a unique word in the error I just sit down in a quiet corner and softly cry". 3) It allows for "layered" error management strategies. I'm not saying it gets it up to OCaml levels, but it is far superior to C or Go error management. In the main function, you catch any Exception for the various parts of the program you start, log it in a reasonable manner, alert if necessary, and restart the relevant portion of the program. Inside the parts of the program you catch finer grained exceptions with more explicit management. 4) it's far more concise. So "explicit" error management ? Let's just be truthful here (just look at Github examples of C and Go code): it's really just ignoring errors. You can find coding errors involving ignored errors in the Go standard library in minutes. Examples: 1) https://github.com/golang/go/blob/master/src/bufio/bufio.go#... 2) https://github.com/golang/go/blob/master/src/bufio/bufio.go#... 3) https://github.com/golang/go/blob/master/src/flag/flag.go#L5... So even the Go core developers themselves can't be trusted to not ignore errors. |
...huh? No, I'm not saying that. I'm saying that if you write a shell script there's a risk of not detecting errors that you care about. I also said that I like to rewrite these overgrown shell scripts in Go, which is apparently a Wrong Opinion and some bad C code will somehow convince me of this.
First, the nitpicks: EAGAIN should not be handled here. EAGAIN shouldn't be retried in a loop, that will just spin the CPU for no good reason. If printf() returns EAGAIN it means that you made stdout non-blocking and hopefully you would know if you did that, but that's unusual except in language runtimes. There's also a missing break; in the switch.
Beyond that, I don't really care about error handling for printf() when I'm logging output or running interactive programs.
Compare this with the behavior for C++:
Try it yourself.As an example of the errors we see in our logs, they often look like this:
The "ignored errors in the Go standard library" aren't really ignored errors. Look at the bufio code a little bit more closely, you'll see that those errors are properly returned.