-
Notifications
You must be signed in to change notification settings - Fork 18.7k
Description
This is a counter-proposal to #32437
Proposal: A built-in Go error check function, catch
catch would function much like the proposed try with a few specific differences:
1.) catch would not return any values, meaning it must be on a line by itself, like panic()
2.) catch takes 1..N arguments
2a.) the first argument must be of type error
2b.) The remainder of the arguments are optional and wrap the error using the given format string and args, as if sent through the new fmt.Errorf which does error wrapping similar to github.com/pkg/errors.
e.g.
func getConfig(config string) (*Config, error)
f, err := os.Open(config)
catch(err)
defer f.Close()
// use f to make a c *Config...
return c, nil
}In this code, catch is the equivalent of
if err != nil {
return nil, err
}If err is non-nil, it will return zero values for all other return values, just like try. The difference being that since catch doesn't return values, you can't "hide" it on the right hand side. You also can't nest catch inside another function, and the only function you can nest inside of catch is one that just returns an error. This is to ensure readability of the code.
This makes catch just as easy to see in the flow of the code as if err != nil is now. It means you can't magically exit from a function in the middle of a line if something fails. It removes nesting of functions which is otherwise usually rare and discouraged in go code, for readability reasons.
This almost makes catch like a keyword, except it's backwards compatible with existing code in case someone already has the name catch defined in their code (though I think others have done homework saying try and catch are both rarely used names in Go code).
Optionally, you can add more data to an error in the same line as catch:
func getConfig(user, config string) (*Config, error)
f, err := os.Open(config)
catch(err, "can't open config for user %s", user)
defer f.Close()
// use f to make a c * Config...
return c, nil
}In this configuration, catch is equivalent to
if err != nil {
return nil, fmt.Errorf("can't open config for user %s: %v", user, err)
}And would utilize the new implicit error wrapping.
This proposal accomplishes 3 things:
1.) It reduces if err != nil boilerplate
2.) It maintains current legibility of exit points of a function having to be indicated by the first word on the line
3.) It makes it easier to annotate errors than either if err != nil or the try proposal.