Skip to content

Instantly share code, notes, and snippets.

@morikuni
Last active December 20, 2018 20:24
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save morikuni/bbe4b2b0384507b42e6a79d4eca5fc61 to your computer and use it in GitHub Desktop.
Save morikuni/bbe4b2b0384507b42e6a79d4eca5fc61 to your computer and use it in GitHub Desktop.
Go 2 Error Handling - function and syntactic sugar
// ParseError wraps err with parse error message.
func ParseError(err error) error { return errors.Wrap(err, “parse error“) }
// WithMessagse wraps err with arbitrary message.
func WithMessage(message string) func(err error) error {
return func(err error) error { returns errors.Wrap(err, message) }
}
// Ignore ignores err.
func Ignore(_ error) error { return nil }
// MultiError aggregates multiple errors.
type MultiError struct {
Errors []error
}
// Append appends err to the error list.
func (me *MultiError) Append(err error) error {
me.Errors = append(me.Errors, err)
return nil
}
// Error is for error interface.
func (me *MultiError) Error() string {
return "multi error"
}
func doSomething() error {
i1 := check ParseError strconv.ParseInt(“123”, 10, 64)
i2 := check WithMessage(“parse error”) strconv.ParseInt(“123”, 10, 64)
i3 := check Ignore strconv.ParseInt(“123”, 10, 64)
me := &MultiError{}
i4 := check me.Append strconv.ParseInt(“123”, 10, 64)
i5 := check me.Append strconv.ParseInt(“456”, 10, 64)
if me.Errors != nil {
return me
}
return nil
}
@morikuni
Copy link
Author

morikuni commented Sep 29, 2018

My proposal is "Use functions as an error handler, Add syntactic sugar to remove duplicated if statement".

check is a syntactic sugar.
check takes a function func(error) error and call it only when the err is not nil.
check returns err with zero values if the function returned a non-nil error.

v1, v2, ..., vN, err := chack <f func(error) error> <expr>
if err != nil {
	if err2 := f(err); err2 != nil {
		return zero1, zero2, ..., zeroN, err2
	}
}

For example.

i2 := check WithMessage(“parse error”) strconv.ParseInt(“123”, 10, 64)

The above code equals to below.

i1, err := strconv.ParseInt(“123”, 10, 64)
if err != nil {
	if err2 := WithMessage(“parse error”)(err); err2 != nil {
		return err2
	}
}

I think the name check is not the best, because it is widely used in existing code, but I have no good idea.

@haasted
Copy link

haasted commented Dec 20, 2018

I've been skimming through the various proposals for Go 2 error handling, and I think this one is my favourite so far. Including the "official" proposal. Thanks for writing it up.

I love that it keeps things verbose about what's happening, while still providing full flexibility for handlers.

Did you ever consider using a syntax in the style of i4 := strconv.ParseInt(“123”, 10, 64) ? me.Append to keep the actual function call at the front of the line?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment