Skip to content

Commit 6147ae6

Browse files
authored
Merge pull request #119 from dyweb/errors/go1.13
[errors] Align interface with go1.13 - Add `Unwrap` and `As` - Remove `DirectCause`
2 parents 887d172 + 0a70edf commit 6147ae6

16 files changed

+184
-67
lines changed

.travis.yml

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,7 @@ language: go
22
sudo: false
33

44
go:
5-
- "1.11"
6-
- "1.12"
5+
- "1.13"
76
- tip
87

98
env:

errors/README.md

Lines changed: 9 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,24 @@
11
# Errors
22

3-
A error package that allows you to wrap/unwrap, multi error and inspect error
3+
[![GoDoc](https://godoc.org/github.com/dyweb/gommon/errors?status.svg)](https://godoc.org/github.com/dyweb/gommon/errors)
4+
5+
A replacement for `errors` and `pkg/errors`. Supports error wrapping, inspection and multi errors.
6+
7+
- [Survey](doc/survey)
48

59
## Issues
610

711
- [#54](https://github.com/dyweb/gommon/issues/54) init
12+
- [#62](https://github.com/dyweb/gommon/issues/62) support fmt.Formatter
813

914
## Implementation
1015

1116
- [doc/design](doc/design) contains some survey and design choices we made
12-
- `Wrap` checks if this is already a `WrappedErr`, if not, it attach stack
17+
- `Wrap` checks if this is already a `WrappedErr`, if not, it attaches stack
1318
- `MultiErr` keep a slice of errors, the thread safe version use mutex and returns copy of slice when `Errors` is called
1419

15-
## Survey
16-
17-
- Wrap error with context (stack, cause etc.)
18-
- [pkg/errors](doc/pkg-errors.md)
19-
- Wrap() add withStack only if no cause with stack present https://github.com/pkg/errors/pull/122/
20-
- [juju/errors](doc/juju-errors.md)
21-
- [hashicorp/errwrap](doc/hashicorp-errwrap.md)
22-
- [ ] https://godoc.org/github.com/gorilla/securecookie#Error
23-
- Multi errors
24-
- [hashicorp/go-multierror](doc/hashicorp-go-multierror.md)
25-
- [uber/multierr](doc/uber-multierr.md)
26-
- Wish we could tell if the append happened https://github.com/uber-go/multierr/issues/21
27-
- [ ] https://godoc.org/github.com/gorilla/securecookie#MultiError
28-
2920
## References and Alternatives
3021

3122
- [golang/xerrors](https://github.com/golang/xerrors) Official error wrapping `fmt.Errorf("oh my %w", err)`
32-
- [rotisserie/eris](https://github.com/rotisserie/eris)
23+
- [rotisserie/eris](https://github.com/rotisserie/eris)
24+
- [go-rewrap-errors](https://github.com/xdg-go/go-rewrap-errors) Conver pkg/errors to standard library wrapping

errors/cause.go

Lines changed: 2 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ type causer interface {
1313
// If you want get direct cause, use DirectCause.
1414
// If error is nil, it will return nil. If error is not wrapped it will return the error itself.
1515
// error wrapped using https://github.com/pkg/errors also satisfies this interface and can be unwrapped as well.
16-
// TODO: might consider rename it to Unwrap since we are deprecating causer interface
16+
// Deprecated: Use Walk if you need root cause or Unwrap if you need direct cause.
1717
func Cause(err error) error {
1818
if err == nil {
1919
return nil
@@ -29,21 +29,4 @@ func Cause(err error) error {
2929
}
3030
}
3131
return err
32-
}
33-
34-
// DirectCause returns the direct cause of the error (if any).
35-
// It does NOT follow the cause chain all the way down, just the first one (if any),
36-
// If you want to get root cause, use Cause
37-
func DirectCause(err error) error {
38-
if err == nil {
39-
return nil
40-
}
41-
switch err.(type) {
42-
case Wrapper:
43-
return err.(Wrapper).Unwrap()
44-
case causer:
45-
return err.(causer).Cause()
46-
default:
47-
return err
48-
}
49-
}
32+
}

errors/cause_test.go

Lines changed: 1 addition & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -21,18 +21,4 @@ func TestCause(t *testing.T) {
2121

2222
stderr := stderrors.New("std")
2323
assert.Equal(t, stderr, errors.Cause(stderr))
24-
}
25-
26-
func TestDirectCause(t *testing.T) {
27-
assert.Nil(t, errors.DirectCause(nil))
28-
29-
errw := errors.Wrap(os.ErrClosed, "can't open closed file")
30-
errww := errors.Wrap(errw, "wrap again")
31-
assert.Equal(t, os.ErrClosed, errors.Cause(errww))
32-
assert.Equal(t, os.ErrClosed, errors.Cause(errw))
33-
assert.NotEqual(t, os.ErrClosed, errors.DirectCause(errww))
34-
assert.Equal(t, "can't open closed file", errors.DirectCause(errww).(errors.Messenger).Message())
35-
36-
stderr := stderrors.New("std")
37-
assert.Equal(t, stderr, errors.DirectCause(stderr))
38-
}
24+
}
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
# 2020-01-17 Go1.13 errors
2+
3+
Since go 1.13, the standard `errors` library also ships with error wrapping.
4+
This is a follow up on the old issue [#109](https://github.com/dyweb/gommon/issues/109)
5+
6+
## Working with Errors in Go 1.13
7+
8+
https://blog.golang.org/go1.13-errors
9+
10+
- error can define custom `Is`, kind of like overloading `==` operator
11+
- [ ] can also define custom `As`?
12+
- don't wrap using `%w` if you don't want user to inspect
13+
- wrap sentinel error instead of returning it directly
14+
15+
## Implementation
16+
17+
Is
18+
19+
- checks if errors are comparable before comparing them
20+
- allows err to define a `Is` method, it does not allow target to define `Is` though.
21+
- it didn't define a public interface for `Is` and uses `interface{ Is(error) bool }` instead
22+
23+
```go
24+
func Is(err, target error) bool {
25+
if target == nil {
26+
return err == target
27+
}
28+
29+
isComparable := reflectlite.TypeOf(target).Comparable()
30+
for {
31+
if isComparable && err == target {
32+
return true
33+
}
34+
if x, ok := err.(interface{ Is(error) bool }); ok && x.Is(target) {
35+
return true
36+
}
37+
// TODO: consider supporing target.Is(err). This would allow
38+
// user-definable predicates, but also may allow for coping with sloppy
39+
// APIs, thereby making it easier to get away with them.
40+
if err = Unwrap(err); err == nil {
41+
return false
42+
}
43+
}
44+
}
45+
```
46+
47+
As
48+

errors/doc/survey/README.md

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
# Survey of go error handling libraries
2+
3+
- Wrap error with context (stack, cause etc.)
4+
- [pkg/errors](pkg-errors.md)
5+
- Wrap() add withStack only if no cause with stack present https://github.com/pkg/errors/pull/122/
6+
- [juju/errors](juju-errors.md)
7+
- [hashicorp/errwrap](hashicorp-errwrap.md)
8+
- [ ] https://godoc.org/github.com/gorilla/securecookie#Error
9+
- Multi errors
10+
- [hashicorp/go-multierror](hashicorp-go-multierror.md)
11+
- [uber/multierr](uber-multierr.md)
12+
- Wish we could tell if the append happened https://github.com/uber-go/multierr/issues/21
13+
- [ ] https://godoc.org/github.com/gorilla/securecookie#MultiError
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.

0 commit comments

Comments
 (0)