Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Rethinking Errors in Go

Rethinking Errors in Go

We're starting to think about Go 2. This talk addresses some of the current issues with handling errors in Go. We introduce a burner package that addresses these issues by introducing a unified model of error, defer, and panic. Although this package can simplify Go code today, we hope that experience with this package can help us understand how error handling can be improved at the language level.

176b7829aecb44328ebd28c1a65d7d3f?s=128

Marcel van Lohuizen

November 06, 2017
Tweet

Transcript

  1. Rethinking Errors in Go Marcel van Lohuizen Go core team

  2. r, err := os.Open(“foo.txt”) if err != nil { return

    fmt.Errorf(“oops: %v”, err) } defer r.Close()
  3. Semantics first! Why? 
 error handling can be tricky

  4. func writeToGS(c net.Context, bkt, dst string, r io.Reader) (err error)

    { 
 w := client.Bucket(bkt).Object(dst).NewWriter(c) defer w.CloseWithError(err) if _, err = io.Copy(w, r); err != nil { return fmt.Errorf(“oops: %v”, err)
 } return nil }
  5. func writeToGS(c net.Context, bkt, dst string, r io.Reader) (err error)

    { err = errPanicking w := client.Bucket(bkt).Object(dst).NewWriter(c) defer w.CloseWithError(err) if _, err = io.Copy(w, r); err != nil { return fmt.Errorf(“oops: %v”, err)
 } return err } var errPanicking = errors.New(“panicking”) handle panic FAIL
  6. func writeToGS(c net.Context, bkt, dst string, r io.Reader) (err error)

    { 
 w := client.Bucket(bkt).Object(dst).NewWriter(c) err = errPanicking defer func() { if err != nil { _ = w.CloseWithError(err) } else if err = w.Close(); err != nil { err = fmt.Errorf(“oh noes: %v”, err)
 } } if _, err = io.Copy(w, r); err != nil { return fmt.Errorf(“oops: %v”, err)
 } return err } return error from Close FAIL
  7. func writeToGS(c net.Context, bkt, dst string, r io.Reader) (err error)

    { w := client.Bucket(bkt).Object(dst).NewWriter(c) err = errPanicking defer func() { if err != nil { _ = w.CloseWithError(err) } else if err = w.Close(); err != nil { err = fmt.Errorf(“oh noes: %v”, err) } }() if _, err = io.Copy(w, r); err != nil { return fmt.Errorf(“oops: %v”, err) } return nil } var errPanicking = errors.New(“panicking”)
  8. how to approach simplifying this? semantics first!

  9. Close

  10. error

  11. panic error

  12. an error is recoverable panic is not 
 (sort of)

  13. there is overlap not recognized in Go

  14. Burner package
 (github.com/mpvl/errc)

  15. funnel all errors, including panics, to a single error variable

  16. func writeToGS(c net.Context, bkt, dst string, r io.Reader) (err error)

    { e := errc.Catch(&err) defer e.Handle()
 w := client.Bucket(bkt).Object(dst).NewWriter(c) e.Defer(w.CloseWithError, msg(“oh noes”)) _, err = io.Copy(w, r) e.Must(err, msg(“oh no”)) return nil }
  17. semantics first pays off!

  18. Try it out! Feedback Welcome! Marcel van Lohuizen, Go core

    Team github.com/mpvl/errc github.com/mpvl/errd @mpvl_