content: add blog post on Go 1.13 errors

Change-Id: Id28d46ced8397a96635961ec52256592a5a59594
Reviewed-on: https://go-review.googlesource.com/c/blog/+/201577
Reviewed-by: Damien Neil <dneil@google.com>
diff --git a/content/go1.13-errors.article b/content/go1.13-errors.article
new file mode 100644
index 0000000..904b0eb
--- /dev/null
+++ b/content/go1.13-errors.article
@@ -0,0 +1,345 @@
+Working with Errors in Go 1.13
+17 Oct 2019
+Tags: errors, technical
+
+Damien Neil and Jonathan Amsterdam
+
+* Introduction
+
+Go’s treatment of [[https://blog.golang.org/errors-are-values][errors as values]]
+has served us well over the last decade. Although the standard library’s support
+for errors has been minimal—just the `errors.New` and `fmt.Errorf` functions,
+which produce errors that contain only a message—the built-in `error` interface
+allows Go programmers to add whatever information they desire. All it requires
+is a type that implements an `Error` method:
+
+
+    type QueryError struct {
+        Query string
+        Err   error
+    }
+
+    func (e *QueryError) Error() string { return e.Query + ": " + e.Err.Error() }
+
+Error types like this one are ubiquitous, and the information they store varies
+widely, from timestamps to filenames to server addresses. Often, that
+information includes another, lower-level error to provide additional context.
+
+The pattern of one error containing another is so pervasive in Go code that,
+after [[https://golang.org/issue/29934][extensive discussion]], Go 1.13 added
+explicit support for it. This post describes the additions to the standard
+library that provide that support: three new functions in the `errors` package,
+and a new formatting verb for `fmt.Errorf`.
+
+Before describing the changes in detail, let's review how errors are examined
+and constructed in previous versions of the language.
+
+* Errors before Go 1.13
+
+** Examining errors
+
+Go errors are values. Programs make decisions based on those values in a few
+ways. The most common is to compare an error to `nil` to see if an operation
+failed.
+
+    if err != nil {
+        // something went wrong
+    }
+
+Sometimes we compare an error to a known _sentinel_ value, to see if a specific error has occurred.
+
+    var ErrNotFound = errors.New("not found")
+
+    if err == ErrNotFound {
+        // something wasn't found
+    }
+
+An error value may be of any type which satisfies the language-defined `error`
+interface. A program can use a type assertion or type switch to view an error
+value as a more specific type.
+
+    type NotFoundError struct {
+        Name string
+    }
+
+    func (e *NotFoundError) Error() string { return e.Name + ": not found" }
+
+    if e, ok := err.(*NotFoundError); ok {
+        // e.Name wasn't found
+    }
+
+
+** Adding information
+
+Frequently a function passes an error up the call stack while adding information
+to it, like a brief description of what was happening when the error occurred. A
+simple way to do this is to construct a new error that includes the text of the
+previous one:
+
+    if err != nil {
+        return fmt.Errorf("decompress %v: %v", name, err)
+    }
+
+Creating a new error with `fmt.Errorf` discards everything from the original
+error except the text. As we saw above with `QueryError`, we may sometimes want
+to define a new error type that contains the underlying error, preserving it for
+inspection by code. Here is `QueryError` again:
+
+
+    type QueryError struct {
+        Query string
+        Err   error
+    }
+
+Programs can look inside a `*QueryError` value to make decisions based on the
+underlying error. You'll sometimes see this referred to as "unwrapping" the
+error.
+
+    if e, ok := err.(*QueryError); ok && e.Err == ErrPermission {
+        // query failed because of a permission problem
+    }
+
+
+The `os.PathError` type in the standard library is another example of one error which contains another.
+
+* Errors in Go 1.13
+
+** The Unwrap method
+
+Go 1.13 introduces new features to the `errors` and `fmt` standard library
+packages to simplify working with errors that contain other errors. The most
+significant of these is a convention rather than a change: an error which
+contains another may implement an `Unwrap` method returning the underlying
+error. If `e1.Unwrap()` returns `e2`, then we say that `e1` _wraps_ `e2`, and
+that you can _unwrap_ `e1` to get `e2`.
+
+Following this convention, we can give the `QueryError` type above an `Unwrap`
+method that returns its contained error:
+
+    func (e *QueryError) Unwrap() error { return e.Err }
+
+The result of unwrapping an error may itself have an `Unwrap` method; we call
+the sequence of errors produced by repeated unwrapping the _error_chain_.
+
+** Examining errors with Is and As
+
+The Go 1.13 `errors` package includes two new functions for examining errors: `Is` and `As`. 
+
+The `errors.Is` function compares an error to a value.
+
+    // Similar to:
+    //   if err == ErrNotFound { … }
+    if errors.Is(err, ErrNotFound) {
+        // something wasn't found
+    }
+
+The `As` function tests whether an error is a specific type.
+
+    // Similar to:
+    //   if e, ok := err.(*QueryError); ok { … }
+    var e *QueryError
+    if errors.As(err, &e) {
+        // err is a *QueryError, and e is set to the error's value
+    }
+
+In the simplest case, the `errors.Is` function behaves like a comparison to a
+sentinel error, and the `errors.As` function behaves like a type assertion. When
+operating on wrapped errors, however, these functions consider all the errors in
+a chain. Let's look again at the example from above of unwrapping a `QueryError`
+to examine the underlying error:
+
+    if e, ok := err.(*QueryError); ok && e.Err == ErrPermission {
+        // query failed because of a permission problem
+    }
+
+Using the `errors.Is` function, we can write this as:
+
+    if errors.Is(err, ErrPermission) {
+        // err, or some error that it wraps, is a permission problem
+    }
+
+
+The `errors` package also includes a new `Unwrap` function which returns the
+result of calling an error's `Unwrap` method, or `nil` when the error has no
+`Unwrap` method. It is usually better to use `errors.Is` or `errors.As`,
+however, since these functions will examine the entire chain in a single call.
+
+** Wrapping errors with %w
+
+As mentioned earlier, it is common to use the `fmt.Errorf` function to add additional information to an error.
+
+    if err != nil {
+        return fmt.Errorf("decompress %v: %v", name, err)
+    }
+
+In Go 1.13, the `fmt.Errorf` function supports a new `%w` verb. When this verb
+is present, the error returned by `fmt.Errorf` will have an `Unwrap` method
+returning the argument of `%w`, which must be an error. In all other ways, `%w`
+is identical to `%v`.
+
+    if err != nil {
+        // Return an error which unwraps to err.
+        return fmt.Errorf("decompress %v: %w", name, err)
+    }
+
+Wrapping an error with `%w` makes it available to `errors.Is` and `errors.As`:
+
+    err := fmt.Errorf("access denied: %w”, ErrPermission)
+    ...
+    if errors.Is(err, ErrPermission) ...
+
+
+** Whether to Wrap
+
+When adding additional context to an error, either with `fmt.Errorf` or by
+implementing a custom type, you need to decide whether the new error should wrap
+the original. There is no single answer to this question; it depends on the
+context in which the new error is created. Wrap an error to expose it to
+callers. Do not wrap an error when doing so would expose implementation details.
+
+As one example, imagine a `Parse` function which reads a complex data structure
+from an `io.Reader`. If an error occurs, we wish to report the line and column
+number at which it occurred. If the error occurs while reading from the
+`io.Reader`, we will want to wrap that error to allow inspection of the
+underlying problem. Since the caller provided the `io.Reader` to the function,
+it makes sense to expose the error produced by it.
+
+In contrast, a function which makes several calls to a database probably should
+not return an error which unwraps to the result of one of those calls. If the
+database used by the function is an implementation detail, then exposing these
+errors is a violation of abstraction. For example, if the `LookupUser` function
+of your package `pkg` uses Go's `database/sql` package, then it may encounter a
+`sql.ErrNoRows` error. If you return that error with
+`fmt.Errorf("accessing`DB:`%v",`err)`
+then a caller cannot look inside to find the `sql.ErrNoRows`. But if
+the function instead returns `fmt.Errorf("accessing`DB:`%w",`err)`, then a
+caller could reasonably write
+
+    err := pkg.LookupUser(...)
+    if errors.Is(err, sql.ErrNoRows) …
+
+At that point, the function must always return `sql.ErrNoRows` if you don't want
+to break your clients, even if you switch to a different database package. In
+other words, wrapping an error makes that error part of your API. If you don't
+want to commit to supporting that error as part of your API in the future, you
+shouldn't wrap the error.
+
+It’s important to remember that whether you wrap or not, the error text will be
+the same. A _person_ trying to understand the error will have the same information
+either way; the choice to wrap is about whether to give _programs_ additional
+information so they can make more informed decisions, or to withhold that
+information to preserve an abstraction layer.
+
+* Customizing error tests with Is and As methods
+
+The `errors.Is` function examines each error in a chain for a match with a
+target value. By default, an error matches the target if the two are equal. In
+addition, an error in the chain may declare that it matches a target by
+implementing an `Is` _method_.
+
+As an example, consider this error inspired by the
+[[https://commandcenter.blogspot.com/2017/12/error-handling-in-upspin.html][Upspin error package]]
+which compares an error against a template, considering only fields which are
+non-zero in the template:
+
+    type Error struct {
+        Path string
+        User string
+    }
+
+    func (e *Error) Is(target error) bool {
+        t, ok := target.(*Error)
+        if !ok {
+            return false
+        }
+        return (e.Path == t.Path || t.Path == "") &&
+               (e.User == t.User || t.User == "")
+    }
+
+    if errors.Is(err, &Error{User: "someuser"}) {
+        // err's User field is "someuser".
+    }
+
+The `errors.As` function similarly consults an `As` method when present.
+
+* Errors and package APIs
+
+A package which returns errors (and most do) should describe what properties of
+those errors programmers may rely on. A well-designed package will also avoid
+returning errors with properties that should not be relied upon.
+
+The simplest specification is to say that operations either succeed or fail,
+returning a nil or non-nil error value respectively. In many cases, no further
+information is needed.
+
+If we wish a function to return an identifiable error condition, such as "item
+not found," we might return an error wrapping a sentinel.
+
+    var ErrNotFound = errors.New("not found")
+
+    // FetchItem returns the named item.
+    //
+    // If no item with the name exists, FetchItem returns an error
+    // wrapping ErrNotFound.
+    func FetchItem(name string) (*Item, error) {
+        if itemNotFound(name) {
+            return nil, fmt.Errorf("%q: %w", name, ErrNotFound)
+        }
+        // ...
+    }
+
+There are other existing patterns for providing errors which can be semantically
+examined by the caller, such as directly returning a sentinel value, a specific
+type, or a value which can be examined with a predicate function.
+
+In all cases, care should be taken not to expose internal details to the user.
+As we touched on in "Whether to Wrap" above, when you return
+an error from another package you should convert the error to a form that does
+not expose the underlying error, unless you are willing to commit to returning
+that specific error in the future.
+
+    f, err := os.Open(filename)
+    if err != nil {
+        // The *os.PathError returned by os.Open is an internal detail.
+        // To avoid exposing it to the caller, repackage it as a new
+        // error with the same text. We use the %v formatting verb, since
+        // %w would permit the caller to unwrap the original *os.PathError.
+        return fmt.Errorf("%v", err)
+    }
+
+If a function is defined as returning an error wrapping some sentinel or type,
+do not return the underlying error directly.
+
+    var ErrPermission = errors.New("permission denied")
+
+    // DoSomething returns an error wrapping ErrPermission if the user
+    // does not have permission to do something.
+    func DoSomething() {
+        if !userHasPermission() {
+            // If we return ErrPermission directly, callers might come
+            // to depend on the exact error value, writing code like this:
+            //
+            //     if err := pkg.DoSomething(); err == pkg.ErrPermission { … }
+            //
+            // This will cause problems if we want to add additional
+            // context to the error in the future. To avoid this, we
+            // return an error wrapping the sentinel so that users must
+            // always unwrap it:
+            //
+            //     if err := pkg.DoSomething(); errors.Is(err, pkg.ErrPermission) { ... }
+            return fmt.Errorf("%w", ErrPermission)
+        }
+        // ...
+    }
+
+* Conclusion
+
+Although the changes we’ve discussed amount to just three functions and a
+formatting verb, we hope they will go a long way toward improving how errors are
+handled in Go programs. We expect that wrapping to provide additional context
+will become commonplace, helping programs to make better decisions and helping
+programmers to find bugs more quickly.
+
+As Russ Cox said in his [[https://blog.golang.org/experiment][GopherCon 2019 keynote]],
+on the path to Go 2 we experiment, simplify and ship. Now that we’ve
+shipped these changes, we look forward to the experiments that will follow.