3 ms·
This proposal by deanveloper is the best I've seen against try. (apologies for indentation change - not sure why hn can't preserve it) https://github.com/golan
by pleasenotry 7y ago
This proposal by deanveloper is the best I've seen against try.
(apologies for indentation change - not sure why hn can't preserve it)
https://github.com/golang/go/issues/32437#issuecomment-498932961 https://github.com/golang/go/issues/32437#issuecomment-49893...
________________________________________________________________
I actually really like this proposal. However, I do have one criticism. The exit point of functions in Go have always been marked by a return. Panics are also exit points, however those are catastrophic errors that are typically not meant to ever be encountered.
Making an exit point of a function that isn't a return, and is meant to be commonplace, may lead to much less readable code. I had heard about this in a talk and it is hard to unsee the beauty of how this code is structured:
//
func CopyFile(src, dst string) error {
r, err := os.Open(src)
if err != nil {
return fmt.Errorf("copy %s %s: %v", src, dst, err)
}
defer r.Close()
w, err := os.Create(dst)
if err != nil {
return fmt.Errorf("copy %s %s: %v", src, dst, err)
}
if _, err := io.Copy(w, r); err != nil {
w.Close()
os.Remove(dst)
return fmt.Errorf("copy %s %s: %v", src, dst, err)
}
if err := w.Close(); err != nil {
os.Remove(dst)
return fmt.Errorf("copy %s %s: %v", src, dst, err)
}
}
//
This code may look like a big mess, and was meant to by the error handling draft, but let's compare it to the same thing with try.
//
func CopyFile(src, dst string) error {
defer func() {
err = fmt.Errorf("copy %s %s: %v", src, dst, err)
}()
r, err := try(os.Open(src))
defer r.Close()
w, err := try(os.Create(dst))
defer w.Close()
defer os.Remove(dst)
try(io.Copy(w, r))
try(w.Close())
return nil
}
//
You may look at this at first glance and think it looks better, because there is a lot less repeated code. However, it was very easy to spot all of the spots that the function returned in the first example. They were all indented and started with return, followed by a space. This is because of the fact that all conditional returns must be inside of conditional blocks, thereby being indented by gofmt standards. return is also, as previously stated, the only way to leave a function without saying that a catastrophic error occurred. In the second example, there is only a single return, so it looks like the only thing that the function ever should return is nil. The last two try calls are easy to see, but the first two are a bit harder, and would be even harder if they were nested somewhere, ie something like proc := try(os.FindProcess(try(strconv.Atoi(os.Args[1])))).
Returning from a function has seemed to have been a "sacred" thing to do, which is why I personally think that all exit points of a function should be marked by return.
- sacado2 7y agoThat's a very good point.
- qtplatypus 7y agoAt first glance I can tell where the code exits. It happens whenever there is a "return" or a "try".