3. There
are
anima;ons
of
Nathan
and
I
coming
in
and
out
during
the
story.
• Nathan
is
a
friend
of
mine
who
contributes
to
the
fsno;fy
package,
he
has
done
some
great
things
for
the
community.
3
4. • Nathan
was
online
in
Slack
asking
ques;ons
about
error
handling.
• So,
I
did
what
any
friend
would
do,
I
jumped
into
the
conversa;on.
• AFer
talking
for
a
bit
he
showed
me
some
code
similar
to
this.
• When
I
saw
this
it
just
didn’t
feel
right.
• This
seemed
way
to
complicated
but
I
couldn’t
put
my
finger
on
it.
4
5. • I
realized
aFer
months
of
coding
in
Go
I
had
no
idea
how
errors
worked.
• I
saw
errors
in
Go
as
string
messages,
there
had
to
be
more.
• Testament
to
Go
that
you
don’t
need
to
know
all
the
details.
• Bad
experience
with
custom
error
types
in
C++
and
C#
• Custom
error
types
were
not
prevalent
but
they
did
exist
in
the
standard
library.
• To
be
effec;ve,
let’s
learn
how
errors
really
work
in
Go.
**
Next
Slide
–
Think
About
This
**
5
6. • This
is
what
I
want
you
to
take
away
from
this
talk.
6
7. • Share
two
thoughts.
• This
is
the
basis
for
how
I
look
at
error
handling.
7
8. How
we
decide
to
create
our
error
values
should
be
based
on
this
idea.
8
11. • Helps
to
clarify
how
to
think
about
errors
in
Go.
• Errors
are
values,
values
that
need
to
be
handled
as
errors
happen.
• Not
as
an
aFer
thought
or
something
to
be
handled
later.
11
12. • A
common
pa]ern
in
Go.
• The
error
value
returned
is
checked
against
the
value
of
nil.
• If
the
error
value
is
not
nil,
then
an
error
occurred
and
all
other
values
are
ignored.
• The
error
is
handled
immediately
and
decisions
are
made
as
to
how
to
proceed.
**
Next
Slide
–
Standard
Library
Support
**
12
14. • The
error
interface
as
declared
by
the
standard
library.
• Contains
a
single
method
called
Error
that
returns
a
string.
• The
interface
is
built
into
the
language.
• Though
it
is
unexported
by
its
name,
we
s;ll
have
access
to
it.
14
15. • Default
implementa;on
of
the
error
interface.
• errorString
is
declared
in
the
errors
package.
• Unexported
struct
with
a
single
unexported
field.
• The
implementa;on
uses
a
pointer
receiver
and
returns
the
value
of
s.
• Most
used
concrete
type
in
the
standard
library
for
error
values.
• The
nature
of
interfaces
make
this
struct
very
effec;ve
in
handling
errors.
15
16. • Use
New
func
to
create
error
values
using
the
struct
as
the
concrete
type.
• Takes
a
string
and
returns
a
pointer
of
type
errorString.
• The
return
type
for
the
New
func;on
is
an
interface
value
of
type
error.
• We
return
a
pointer
of
type
errorString.
• The
caller
receives
is
an
interface
value
of
type
error.
• What
does
the
value
that
the
caller
receives
actually
looks
like?
16
17. • Interface
value
is
always
a
two
machine
word
value.
• It
stores
a
concrete
type
value
that
implements
the
interface.
• When
the
New
func;on
is
an
error
interface
value
is
created
on
the
return
and
the
errorString
pointer
is
stored
within
it.
• The
language
support
abstracts
this
implementa;on
away
and
makes
working
with
these
values
intui;ve.
17
18. • Just
as
a
note.
• This
is
the
value
that
is
actually
returned
for
nil.
• An
interface
value
is
always
returned.
• We
have
like
types
present
on
both
sides
of
the
compare
statement.
18
19. • Second
way
to
create
an
error
interface
value
based
on
the
errorString
struct.
• Use
when
you
need
a
forma]ed
error,
usually
with
local
variables.
• No;ce
the
use
of
the
New
func;on
from
the
errors
package.
**
Next
–
Use
In
Standard
Library
**
19
21. • Let’s
learn
a
technique
used
in
the
standard
library
to
help
us
iden;ty
specific
errors.
• The
error
interface
variables
above
are
declared
in
the
bufio
package.
• They
provide
support
for
iden;fying
specific
errors.
• This
works
when
the
error
messages
are
sta;c.
21
22. • How
to
use
the
error
interface
variables
to
iden;fy
which
error
was
returned
by
the
Peek
func;on.
• The
Peek
func;on
can
return
either
the
ErrNega;veCount
or
ErrBufferFull
error
variable.
• We
use
the
same
variables
to
iden;fy
the
specific
error
returned.
• Make
a
more
informed
error
handling
decision.
22
23. • How
to
use
the
error
interface
variables
to
iden;fy
which
error
was
returned
by
the
Peek
func;on.
• The
Peek
func;on
can
return
either
the
ErrNega;veCount
or
ErrBufferFull
error
variable.
• We
use
the
same
variables
to
iden;fy
the
specific
error
returned.
• Make
a
more
informed
error
handling
decision.
23
24. • Other
packages
like
the
io
package
use
the
same
technique
• I
am
sure
you
have
compared
the
returned
error
interface
value
to
EOF.
24
25. • Here
is
the
implementa;on
of
the
ReadAtLeast
func;on
from
the
io
package.
• We
see
how
these
variables
are
being
returned
• We
see
how
the
EOF
variable
is
used
internally
to
check
for
that
error.
• When
you
need
to
make
a
decision
about
a
specific
error,
check
if
an
error
interface
variable
exists
to
help
you.
**
Next
–
Custom
Error
Types
**
25
26. • How
to
use
the
error
interface
variables
to
iden;fy
which
error
was
returned
by
the
Peek
func;on.
• The
Peek
func;on
can
return
either
the
ErrNega;veCount
or
ErrBufferFull
error
variable.
• We
use
the
same
variables
to
iden;fy
the
specific
error
returned.
• Make
a
more
informed
error
handling
decision.
28. • This
is
a
custom
error
type
implemented
within
the
net
package.
28
29. • This
is
a
custom
error
type
implemented
within
the
net
package.
• The
name
of
the
custom
error
type
follows
the
Go
naming
conven;on
for
custom
error
types.
• The
custom
error
type
should
provide
context
associated
with
the
error
to
help
the
caller
make
a
more
informed
decision.
• The
first
three
fields
provide
context
about
the
network
opera;on
being
performed
when
an
error
occurs.
• The
fourth
field
contains
the
actual
error
that
occurred.
• The
custom
error
type
exists
to
provide
the
context
associated
with
the
error.
29
30. • This
is
the
implementa;on
of
the
error
interface
for
OpError.
• The
context
associated
with
the
error
is
used
to
produce
a
more
detailed
error
message.
• The
context
enhances
the
details
and
produces
an
error
message
with
more
meaning.
30
31. • This
is
a
custom
error
type
implemented
in
the
json
package.
• This
custom
error
type
is
used
to
report
errors
that
occur
when
a
value
can’t
be
decoded
into
a
specific
Go
type.
• In
this
case,
the
type
itself
provides
the
context
and
maintains
state
associated
with
the
error.
31
32. • The
implementa;on
of
the
error
interface
takes
the
state
associated
with
the
error
and
produces
a
detailed
and
context
rich
message.
32
33. • This
custom
error
type
is
used
to
report
when
there
are
invalid
arguments
passed
into
an
unmarshal
call.
• In
this
case,
only
the
type
informa;on
associated
with
the
bad
argument
is
required
to
be
stored.
33
34. • Here
we
see
the
implementa;on
of
the
error
interface
for
this
custom
error
type.
• Again
the
state
associated
with
the
error
is
used
to
produce
an
error
message
with
more
meaning
and
context.
34
35. In
these
cases
• A
custom
error
type
provided
context
beyond
what
the
errors
package
could
provide.
• The
context
helped
the
caller
make
a
more
informed
decision
about
the
error
**
Next
–
Concrete
Type
Iden;fica;on
**
35
37. • This
method
is
called
by
the
exported
Unmarshal
func;on.
• Method
has
the
poten;al
to
return
error
values
of
different
concrete
types.
• Pointers
of
type
UnmarshalTypeError,
InvalidUnmarshalError
or
errorString.
• Each
error
contains
a
different
context
that
is
important
to
know.
• We
want
to
make
an
informed
decision
on
how
to
handle
the
specific
error.
37
38. • Iden;fy
the
concrete
type
is
for
the
stored
value
inside
the
error
interface
value.
• You
can
do
this,
but
there
is
a
be]er
way.
38
39. • The
switch
statement
supports
this
special
syntax.
• An
interface
type
conversion
using
the
keyword
type.
• Declare
case
statements
based
on
the
different
concrete
types
we
want
to
check
for.
39
43. • Introduce
yourself
• I
realized
aFer
months
of
coding
in
Go
I
had
no
idea
how
errors
worked.
• I
saw
errors
in
Go
as
string
messages,
there
had
to
be
more.
• Testament
to
Go
that
you
don’t
need
to
know
all
the
details.
• Bad
experience
with
custom
error
types
in
C++
and
C#
• Custom
error
types
were
not
prevalent
but
they
did
exist
in
the
standard
library.
• To
be
effec;ve,
let’s
learn
how
errors
really
work
in
Go.
43
Editor's Notes
Introduce yourself
Going to tell a quick story.
There are animations of Nathan and I coming in and out during the story.
Nathan is a friend of mine who contributes to the fsnotify package, he has done some great things for the community.
Nathan was online in Slack asking questions about error handling.
So, I did what any friend would do, I jumped into the conversation.
After talking for a bit he showed me some code similar to this.
When I saw this it just didn’t feel right.
This seemed way to complicated but I couldn’t put my finger on it.
I realized after months of coding in Go I had no idea how errors worked.
I saw errors in Go as string messages, there had to be more.
Testament to Go that you don’t need to know all the details.
Bad experience with custom error types in C++ and C#
Custom error types were not prevalent but they did exist in the standard library.
To be effective, let’s learn how errors really work in Go.
** Next Slide – Think About This **
This is what I want you to take away from this talk.
Share two thoughts.
This is the basis for how I look at error handling.
How we decide to create our error values should be based on this idea.
Ask yourself these questions.
** Next – Working With Error Values **
Helps to clarify how to think about errors in Go.
Errors are values, values that need to be handled as errors happen.
Not as an after thought or something to be handled later.
A common pattern in Go.
The error value returned is checked against the value of nil.
If the error value is not nil, then an error occurred and all other values are ignored.
The error is handled immediately and decisions are made as to how to proceed.
** Next Slide – Standard Library Support **
The error interface as declared by the standard library.
Contains a single method called Error that returns a string.
The interface is built into the language.
Though it is unexported by its name, we still have access to it.
Default implementation of the error interface.
errorString is declared in the errors package.
Unexported struct with a single unexported field.
The implementation uses a pointer receiver and returns the value of s.
Most used concrete type in the standard library for error values.
The nature of interfaces make this struct very effective in handling errors.
Use New func to create error values using the struct as the concrete type.
Takes a string and returns a pointer of type errorString.
The return type for the New function is an interface value of type error.
We return a pointer of type errorString.
The caller receives is an interface value of type error.
What does the value that the caller receives actually looks like?
Interface value is always a two machine word value.
It stores a concrete type value that implements the interface.
When the New function is an error interface value is created on the return and the errorString pointer is stored within it.
The language support abstracts this implementation away and makes working with these values intuitive.
Just as a note.
This is the value that is actually returned for nil.
An interface value is always returned.
We have like types present on both sides of the compare statement.
Second way to create an error interface value based on the errorString struct.
Use when you need a formatted error, usually with local variables.
Notice the use of the New function from the errors package.
** Next – Use In Standard Library **
Let’s learn a technique used in the standard library to help us identity specific errors.
The error interface variables above are declared in the bufio package.
They provide support for identifying specific errors.
This works when the error messages are static.
How to use the error interface variables to identify which error was returned by the Peek function.
The Peek function can return either the ErrNegativeCount or ErrBufferFull error variable.
We use the same variables to identify the specific error returned.
Make a more informed error handling decision.
How to use the error interface variables to identify which error was returned by the Peek function.
The Peek function can return either the ErrNegativeCount or ErrBufferFull error variable.
We use the same variables to identify the specific error returned.
Make a more informed error handling decision.
Other packages like the io package use the same technique
I am sure you have compared the returned error interface value to EOF.
Here is the implementation of the ReadAtLeast function from the io package.
We see how these variables are being returned
We see how the EOF variable is used internally to check for that error.
When you need to make a decision about a specific error, check if an error interface variable exists to help you.
** Next – Custom Error Types **
How to use the error interface variables to identify which error was returned by the Peek function.
The Peek function can return either the ErrNegativeCount or ErrBufferFull error variable.
We use the same variables to identify the specific error returned.
Make a more informed error handling decision.
This is a custom error type implemented within the net package.
This is a custom error type implemented within the net package.
The name of the custom error type follows the Go naming convention for custom error types.
The custom error type should provide context associated with the error to help the caller make a more informed decision.
The first three fields provide context about the network operation being performed when an error occurs.
The fourth field contains the actual error that occurred.
The custom error type exists to provide the context associated with the error.
This is the implementation of the error interface for OpError.
The context associated with the error is used to produce a more detailed error message.
The context enhances the details and produces an error message with more meaning.
This is a custom error type implemented in the json package.
This custom error type is used to report errors that occur when a value can’t be decoded into a specific Go type.
In this case, the type itself provides the context and maintains state associated with the error.
The implementation of the error interface takes the state associated with the error and produces a detailed and context rich message.
This custom error type is used to report when there are invalid arguments passed into an unmarshal call.
In this case, only the type information associated with the bad argument is required to be stored.
Here we see the implementation of the error interface for this custom error type.
Again the state associated with the error is used to produce an error message with more meaning and context.
In these cases
A custom error type provided context beyond what the errors package could provide.
The context helped the caller make a more informed decision about the error
** Next – Concrete Type Identification **
This method is called by the exported Unmarshal function.
Method has the potential to return error values of different concrete types.
Pointers of type UnmarshalTypeError, InvalidUnmarshalError or errorString.
Each error contains a different context that is important to know.
We want to make an informed decision on how to handle the specific error.
Identify the concrete type is for the stored value inside the error interface value.
You can do this, but there is a better way.
The switch statement supports this special syntax.
An interface type conversion using the keyword type.
Declare case statements based on the different concrete types we want to check for.
Introduce yourself
I realized after months of coding in Go I had no idea how errors worked.
I saw errors in Go as string messages, there had to be more.
Testament to Go that you don’t need to know all the details.
Bad experience with custom error types in C++ and C#
Custom error types were not prevalent but they did exist in the standard library.
To be effective, let’s learn how errors really work in Go.