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

Go 2 error values today

Go 2 error values today

Last year, the Go team introduced two draft designs related to errors in Go: one introducing new syntax and the other focussing on improved library support. With the help of community feedback, we have turned the latter into a proposal. An implementation, which is planned to be part of Go 1.13, is now in the Go source tree for evaluation. In this talk, I'll explain its design and how to use the new functionality today.

Marcel van Lohuizen

March 25, 2019
Tweet

More Decks by Marcel van Lohuizen

Other Decks in Programming

Transcript

  1. Go 2 Error Values Today
    dotGo 2019
    Marcel van Lohuizen
    Google
    [email protected]
    Gopher by Renée French

    View full-size slide

  2. Previously
    at a theatre
    near you…

    View full-size slide

  3. End users
    Users of errors
    Developers
    Programs

    View full-size slide

  4. informative, succinct,

    possibly localized
    End users
    "ill-behaved gophers abound: hole in fence”
    "overal slecht gemanierde gophers: gat in hek”

    View full-size slide

  5. more detail
    Developers
    ill-behaved gophers abound:

    main.main

    /home/gopher/src/den/main.go:10

    - hole in fence:

    fence.Check

    /home/gopher/src/den/fence/state.go:9

    View full-size slide

  6. Programs
    strings.Contains(err.Error(), "not exists")
    err == io.EOF
    p, ok := err.(*PathError)
    error inspection

    View full-size slide

  7. Error values
    in core
    Today

    View full-size slide

  8. fmt.Errorf
    Common patterns in the core libraries
    if err != nil {
    return fmt.Errorf("whoops: %v", err)
    }

    View full-size slide

  9. fmt.Errorf discards
    information
    fmt.Errorf

    View full-size slide

  10. Custom error type
    Common patterns in the core libraries
    return &PathError{"open", filename, err}
    In core
    p, ok := err.(*PathError)
    if p.Err == ...
    if os.IsPermission(err) {
    Is it an “exists”
    error?
    With helper

    View full-size slide

  11. Lack of standard for error
    wrapping leads to
    awkward code
    Custom error types

    View full-size slide

  12. github.com/pkg/errors
    Enter the community
    gopkg.in/errgo.v2/errors
    github.com/spacemonkeygo/errors
    go.uber.org/multierr
    upspin.io/errors
    github.com/juju/errors
    github.com/go-errors/errors
    github.com/hashicorp/errwrap

    View full-size slide

  13. Poor interoperability
    between the errors of
    these different packages
    fmt.Errorf

    View full-size slide

  14. Body Level One
    Body Level Two
    Body Level Three
    Body Level Four
    Title Text
    Where from here?
    Photo by Javier Allegue Barros on Unsplash

    View full-size slide

  15. Goal
    custom errors
    ==
    good thing

    View full-size slide

  16. Goal
    need a standard and
    interoperability
    • inspection
    • details
    • localizability

    View full-size slide

  17. Body Level One
    Body Level Two
    Body Level Three
    Body Level Four
    Title Text
    Go 1.13
    Photo by Proposal by Nick Youngson CC BY-SA 3.0 ImageCreator on Unsplash

    View full-size slide

  18. Inspection
    Proposal #29934

    View full-size slide

  19. Error inspection: Wrapper
    Programmatic analysis
    package errors
    type Wrapper interface {
    Unwrap() error
    }
    Optional interface
    func (e *PathError) Unwrap() error {
    return e.Err
    }
    Example
    implementation

    View full-size slide

  20. Error Inspection: errors.Is
    Programmatic analysis
    // Is reports whether err or any of the
    // errors in its chain is equal to target.
    func Is(err, target error) bool
    API for sentinel
    comparison
    // was if err == io.EOF {
    if errors.Is(err, io.EOF) {
    Example usage

    View full-size slide

  21. func Cause(err error) error
    This is not:

    View full-size slide

  22. Error inspection
    Programmatic analysis
    if errors.Is(err, os.ErrPermission) {

    }
    Now
    if os.IsPermission(err) {

    }
    Before

    View full-size slide

  23. Error inspection
    Programmatic analysis
    if errors.Is(err, net.ErrTimeout) {

    }
    Now
    if err, ok := err.(net.Error); ok && err.Timeout() {

    }
    Before

    View full-size slide

  24. Error Inspection: errors.As
    Programmatic analysis
    func As(err error, target interface{}) bool
    API for type assertion
    // was if p, ok := err.(*os.PathError); ok {
    var p *os.PathError
    if errors.As(err, &p) {
    if p := (*os.PathError)(nil); errors.As(err, &p) {
    Example usage

    View full-size slide

  25. Printing
    Proposal #29934
    Gopher by Renée French

    View full-size slide

  26. Normal versus Detail
    Common patterns in the core libraries
    ill-behaved gophers abound:

    main.main

    /home/gopher/src/den/main.go:10

    - hole in fence:

    fence.Check

    /home/gopher/src/den/fence/state.go:9
    fmt.Printf("%+v", err)
    fmt.Printf("%v", err)
    ill-behaved gophers abound: hole in fence

    View full-size slide

  27. Error printing: Formatter and Printer
    Formatting
    package errors
    type Formatter interface {
    error
    FormatError(p Printer) (next error)
    }
    type Printer interface {
    Print(args ...interface{})
    Printf(format string, args ...interface{})
    Detail() bool
    }
    Interfaces

    View full-size slide

  28. Error details
    Formatting
    package errors
    func Caller(skip int) Frame
    type Frame struct { … }
    func (f Frame) Format(p *Printer)
    errors.Frame

    View full-size slide

  29. Error Printing: Example
    Formatting
    type PathError struct {
    Op, Path string
    Err error
    frame Frame
    }
    func (e *PathError) FormatError(p errors.Printer) error {
    p.Printf("%s %s", e.Op, e.Path)
    e.frame.Format(p) // Format calls p.Detail
    return e.Err
    }
    func (e *PathError) Error() string { return fmt.Sprint(e) }

    View full-size slide

  30. Body Level One
    Body Level Two
    Body Level Three
    Body Level Four
    Title Text
    Migration
    Photo by Jan-Niclas Aberle on Unsplash
    Adapting to the new standard

    View full-size slide

  31. • support Unwrap and make errors.Is work
    with:

    - os.ErrPermission

    - os.ErrExist

    - os.ErrNotExist

    - …

    • add location information through FormatError
    Core error types

    View full-size slide

  32. • print single stack frame in
    detailed mode
    Changes to errors.New and fmt.Errorf

    View full-size slide

  33. •FormatError to return err for 

    fmt.Errorf("oops: %v", err)

    fmt.Errorf("oops: %s", err)

    •also adds Unwrap for

    fmt.Errorf("oops: %w", err)
    Changes to fmt.Errorf

    View full-size slide

  34. Announcement
    new functionality
    available today:
    golang.org/x/xerrors

    View full-size slide

  35. import "golang.org/x/xerrors"
    type GopherError struct {
    frame xerrors.Frame
    err error
    }
    func (e *GopherError) Format(s fmt.State, verb rune) {
    xerrors.FormatError(e, s, verb)
    }
    func (e *GopherError) FormatError(p xerrors.Printer) error {
    p.Print("ill-behaving gophers abound")
    e.frame.Format(p)
    return err
    }
    func (e *GopherError) Error() string { return fmt.Sprint(e) }
    Using golang.org/x/xerrors

    View full-size slide

  36. @mpvl_
    Thank you

    dotGo 2019
    Marcel van Lohuizen
    Google
    [email protected]
    Gophers by Renée French

    View full-size slide