-
Notifications
You must be signed in to change notification settings - Fork 18.7k
Description
I am here to propose my idea for error handling in Go 2. I do not particularly dislike typing the full err != nil if statement but I understand the problems identified in the problem statement. If a few people think my approach below sounds good, I'll write something for my weblog and follow proper procedures for posting a language change proposal.
I simply propose that we introduce an expect keyword to the language that triggers whenever the expected condition occurs on the specified variable. The variable scope would be limited to the function codeblock as to not conflict with globals and the variable can not be a property on a method if being invoked as such.
Furthermore, these expect statements can stack just as defers do so that we can add on important "back-out" steps as required.
Example time. Before (from the problem statement):
func CopyFile(src, dst string) error {
r, err := os.Open(src)
if err != nil {
return err
}
defer r.Close()
w, err := os.Create(dst)
if err != nil {
return err
}
defer w.Close()
if _, err := io.Copy(w, r); err != nil {
return err
}
if err := w.Close(); err != nil {
return err
}
}After, with expect:
func CopyFile(src, dst string) error {
var err error
expect err != nil {
return fmt.Errorf("copy %s %s: %v", src, dst, err)
}
r, err := os.Open(src)
defer r.Close()
w, err := os.Create(dst)
defer w.Close()
expect err != nil {
os.Remove(dst)
}
err = io.Copy(w, r)
err = w.Close()
return nil
}There are obviously many various ways to make similar functionality, but I feel like if we make a change to the language's error handling, this one is the closest to what I feel like is the "Go" way. We don't repeatedly call out that we are trying something on every line and we don't depend on invisible rules like the last parameter being an error. We keep our code blocks small (as you should) and we explicitly tell each code block what to expect and how to deal with it. As more things need doing, we instruct the runtime what else to do when the expected event takes place.
In the example above, we expect err to become not nil at some point, and when that happens, we always return the error up the stack. Additionally, after we have created a dst file, we must also clean that file up. I think this code gracefully conveys that without much magic and in a way that new coders can quickly understand.