4 ms·
The problem with this attitude is that it ... it's just not true. C-style not true. C, like Go, convinces people they handle errors. And then, when you look in
by candiodari 8y ago
The problem with this attitude is that it ... it's just not true. C-style not true.
C, like Go, convinces people they handle errors. And then, when you look into what that actually means, correctly handling error cases for even trivial problems ... you immediately find out "nope, you're not handling errors, you're ignoring them". C, and Go are very sneaky that way.
1) one of the more common error cases is nil, closely followed by out of memory and zero division ... which in Go causes a panic just like every other language.
So your Go error handling in this case is never going to be executed. If you think you can avoid exceptions, you're lying to yourself. Every last method needs to be ready that a panic gets called at almost any point. Which ... is exactly what the error system was supposed to fix.
2) "If you treat them as "exceptions" rather than the rule, then you will just write flaky software ..."
This sounds nice until you look at Go sources on github. And you see WHY they're not flaky. Do people handle errors more in Go sources than in Java ? The reverse is true !
But Go software is more stable. How can this happen ?
Well, Go defaults to ignoring errors and just continuing whereas Java (and every sane language) defaults to aborting the program rather than letting it run in an unknown state.
To put it more extreme, and more to the point Go just starts "sudo rm -Rf /" when an error happens. The reality is that Go programs just start writing things to the database based on wrong information when an error happens.
3) "As for timeouts, I am not sure why you wouldn't just pass in a context, which already has provisions for a deadline, explicit cancellation, and cancelling further library calls..."
Again, this sounds cool. You can recognize code that actually uses this correctly.
Incorrect (in more ways than one):
if _, err = f.Write(something); err != nil {
return err
}
More correct:
var err error
cont := true
for retry := 0; cont; retry++ {
if retry > max_retries {
return fmt.Errorf("couldn't do X in max retries. Last error was: %v", err)
}
didit := make(chan bool)
go func() {
defer func() {
if r := recover(); r != nil {
err = fmt.Errorf("the call panicked: %v", r)
}
didit <- true;
}
n := 0
for n < len(something) {
i, err = f.Write(something);
if err != nil {
return
}
n += i
}
}
select {
case <-didit:
// Ok, go to next statement
if err == nil {
cont = false
}
case <-ctx.Done():
return fmt.Errorf("context signaled abort")
case <-time.After(timeout):
}
}
Have you seen such a code style ... even once ?
And what will this do ?
f.Write(something)
One of 5 things:
1) it may actually work (one hopes, the common case)
2) it may not write anything
3) it may PARTIALLY write what you asked to be written (including not writing anything at all and returning EAGAIN, which is why the retry logic is not really optional. Frankly you should have a higher max_retries, and ignoring for the EAGAIN case to avoid some very rare circumstances)
4) it may panic
5a) it may block for a long time
5b) it may block forever (and even make your program unkillable. I mean, we've all used NFS, right ?)
What will be your total amount of material to diagnose this problem when it occurs in cases 1-3 ? Nothing whatsoever.
Case 4 ? A large collection of stacktraces. Thankfully usually with the relevant one on top.
5a and 5b ? 100 stacktraces, when you finally kill it (or ... well Go "supports hundreds of thousands goroutines"), one of which is relevant. Well the truth is that it may actually have so many goroutines that it ... well I managed to run out of diskspace once. But it's easily 10 megabytes and more in a real webserver.
- acdha 8y agoI was going to write about how often I saw the res, _ := … error handling punt and wanted to confirm that lack of even a warning but https://play.golang.org/ https://play.golang.org/ really shows how deep the cognitive dissonance goes. The very first example many people are going to see doesn't even acknowledge the possibility of error handling. That would be safe in a language which uses exceptions or something similar or in a language where the type checker forces you to do something with the return value but Go has this odd mix of learning from C and ignoring its most important lessons and treats ignoring errors as less of a problem than an unused import. Simply having an implied if-error-than-panic check any time someone assigns a value which is never checked would go a long way towards turning subtle hard-to-debug failures-at-a-distance into clear failures at the source. Edit: none of the examples on the golang.org homepage handle errors. You appear to have to go into the fourth section of the language tour to find error handling first being discussed 19 pages into the ”Methods and interfaces” section to find error handling discussed at all and even after that point I only saw a couple of subsequent lessons where this looked like a thing which every working developer should be routinely handling (i.e. the web crawler acknowledges that fetching network resources can fail).
- Groxx 8y agoThe lack of "solves this problem in a mature way" examples in the official tutorials / documentation is IMO a big part of why people think Go code is simpler. Of course it's simpler if you ignore things. Or don't respect cancellation signals. But you shouldn't do that. And once you do, Go starts to get incredibly verbose and error-prone, and you have relatively weak tools for reducing that duplication.
- lloeki 8y ago> the res, _ := … error handling punt and wanted to confirm that lack of even a warning Warnings don't exist in go build, because warnings are ignored by people. IIRC there are linters that do highlight those if you care for it and want hints about things to check. There are legitimate use cases of swallowing error return values†, and if you throw warnings intros cases, then you can't tell the difference between a legit warning and a legit use case that shouldn't warn. > none of the examples on the golang.org homepage handle error. You appear to have to go into the fourth section of the language tour to find error handling first being discussed 19 pages into the ”Methods and interfaces” section Skimming over the fact that this is a "Tour of Go", not a full-blown tutorial, there is not a single call that would return an error before the page you mentioned. There are ok return values for map fetches and type assertions before that though, but they're just printed out, and the same pattern continues afterwards. Those are focused code snippets to show features and get the vibe of things. I certainly wouldn't expect from a tour (for any language) to be the equivalent of The Go Programming Language book, nor Effective Go[0]. [0]: https://golang.org/doc/effective_go.html#errors https://golang.org/doc/effective_go.html#errors † It happens that by design you may have the guarantee that e.g ParseInt will work because you're under full control of the input type and/or value.