3 ms·
>>3 > Why is that unclear? The usual advice is to follow what the stdlib does. Let's look at an example. Let's say we close a file and then try to set a deadl
by TheDong 3y ago
>>3
> Why is that unclear?
The usual advice is to follow what the stdlib does. Let's look at an example. Let's say we close a file and then try to set a deadline on it:
f, _ := os.Create("/tmp/filename")
f.Close()
fmt.Printf("%v", f.SetDeadline(time.Now()))
// output: use of closed file
Okay, so in this case, it's the caller's responsibility to keep track of the filename and add the context of what file was already closed, resulting in that error.
However, what about the error for trying to write to a closed file?
_, err := f.Write(nil)
fmt.Printf("%v", err)
// output: write /tmp/filename: file already closed
Oh, I see, it's Write's responsibility to add the context of the filename. Huh.
This is a clear example of the problem the parent is talking about. The 'os.File' construct knows the filename. Sometimes it adds that as context to errors, sometimes it doesn't. Sometimes the caller needs to add it in, sometimes the callee has already added it.
- masklinn 3y ago> The usual advice is to follow what the stdlib does. This seems to be a significant problem in general, because gophers want clear direction (after all the language was created specifically for… choices to be limited) so they take quips as gospels, but robpike, rsc, etc… take them more as suggestions / guidance (90/10, possibly even 80/20) to be moderated by taste. I don’t remember which one but I think it was robpike who expressed frustration on one of the recently popular issues / proposals, because the proposal was essentially to legislate one of the more common quips, and they like being able to break those when useful or convenient. I think there was also something similar to your exploration here with zero values, where despite the quip that you should “make the zero value meaningful” multiple standard library modules will straight up panic if fed zero values (a classic example being the File struct, `File.Name()` panics and pretty much every other method returns ErrInvalid, so a zero-valued File is useless, actively problematic, and the source of unnecessary overheads). An other fun one is that you can’t call IsZero on a zero `reflect.Value`, and the error message is quite amazing: panic: call of reflect.Value.IsZero on zero Value You need to carefully read the doc and notice that th middle paragraph documenting Value itself says: > The zero Value represents no value. Its IsValid method returns false, its Kind method returns invalid, its String method returns “<invalid Value>”, and all other methods panic.
- throwaway894345 3y agoI agree, the stdlib is confusing here. A safe rule is just to add the extra context in the caller unless you know the callee adds it. The worst that can happen is you include the file path multiple times and things get noisy.
- jjnoakes 3y agoI agree and I've been thinking about this in general (not only in the context of go, but for programming in general). I've settled on "caller adds context" because it is only the caller who knows if the error can be handled immediately (in which case no context is needed and we save the extra effort of creating it) or if the error should be propagated up, and how (should it be wrapped with context, wrapped in another struct, replaced with a different struct, etc).