Slide 1

Slide 1 text

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

Slide 2

Slide 2 text

Previously at a theatre near you…

Slide 3

Slide 3 text

End users Users of errors Developers Programs

Slide 4

Slide 4 text

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

Slide 5

Slide 5 text

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

Slide 6

Slide 6 text

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

Slide 7

Slide 7 text

Error values in core Today

Slide 8

Slide 8 text

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

Slide 9

Slide 9 text

fmt.Errorf discards information fmt.Errorf

Slide 10

Slide 10 text

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

Slide 11

Slide 11 text

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

Slide 12

Slide 12 text

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

Slide 13

Slide 13 text

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

Slide 14

Slide 14 text

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

Slide 15

Slide 15 text

Goal custom errors == good thing

Slide 16

Slide 16 text

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

Slide 17

Slide 17 text

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

Slide 18

Slide 18 text

Inspection Proposal #29934

Slide 19

Slide 19 text

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

Slide 20

Slide 20 text

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

Slide 21

Slide 21 text

func Cause(err error) error This is not:

Slide 22

Slide 22 text

Error inspection Programmatic analysis if errors.Is(err, os.ErrPermission) { … } Now if os.IsPermission(err) { … } Before

Slide 23

Slide 23 text

Error inspection Programmatic analysis if errors.Is(err, net.ErrTimeout) { … } Now if err, ok := err.(net.Error); ok && err.Timeout() { … } Before

Slide 24

Slide 24 text

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

Slide 25

Slide 25 text

Printing Proposal #29934 Gopher by Renée French

Slide 26

Slide 26 text

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

Slide 27

Slide 27 text

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

Slide 28

Slide 28 text

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

Slide 29

Slide 29 text

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) }

Slide 30

Slide 30 text

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

Slide 31

Slide 31 text

• support Unwrap and make errors.Is work with: - os.ErrPermission - os.ErrExist - os.ErrNotExist - … • add location information through FormatError Core error types

Slide 32

Slide 32 text

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

Slide 33

Slide 33 text

•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

Slide 34

Slide 34 text

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

Slide 35

Slide 35 text

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

Slide 36

Slide 36 text

Community

Slide 37

Slide 37 text

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