Deprecated: Function get_magic_quotes_gpc() is deprecated in /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php on line 99

Deprecated: The each() function is deprecated. This message will be suppressed on further calls in /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php on line 619

Warning: Cannot modify header information - headers already sent by (output started at /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php:99) in /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php on line 1169

Warning: Cannot modify header information - headers already sent by (output started at /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php:99) in /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php on line 1176

Warning: Cannot modify header information - headers already sent by (output started at /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php:99) in /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php on line 1176

Warning: Cannot modify header information - headers already sent by (output started at /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php:99) in /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php on line 1176

Warning: Cannot modify header information - headers already sent by (output started at /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php:99) in /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php on line 1176

Warning: Cannot modify header information - headers already sent by (output started at /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php:99) in /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php on line 1176

Warning: Cannot modify header information - headers already sent by (output started at /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php:99) in /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php on line 1176

Warning: Cannot modify header information - headers already sent by (output started at /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php:99) in /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php on line 1176

Warning: Cannot modify header information - headers already sent by (output started at /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php:99) in /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php on line 1176

Warning: Cannot modify header information - headers already sent by (output started at /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php:99) in /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php on line 1176

Warning: Cannot modify header information - headers already sent by (output started at /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php:99) in /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php on line 1176

Warning: Cannot modify header information - headers already sent by (output started at /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php:99) in /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php on line 1176

Warning: Cannot modify header information - headers already sent by (output started at /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php:99) in /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php on line 1176

Warning: Cannot modify header information - headers already sent by (output started at /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php:99) in /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php on line 1176

Warning: Cannot modify header information - headers already sent by (output started at /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php:99) in /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php on line 1176

Warning: Cannot modify header information - headers already sent by (output started at /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php:99) in /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php on line 1176

Warning: Cannot modify header information - headers already sent by (output started at /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php:99) in /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php on line 1176

Warning: Cannot modify header information - headers already sent by (output started at /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php:99) in /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php on line 1176

Warning: Cannot modify header information - headers already sent by (output started at /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php:99) in /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php on line 1176

Warning: Cannot modify header information - headers already sent by (output started at /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php:99) in /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php on line 1176

Warning: Cannot modify header information - headers already sent by (output started at /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php:99) in /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php on line 1176

Warning: Cannot modify header information - headers already sent by (output started at /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php:99) in /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php on line 1176
8000 Add go 1.13 errors feature support by PeterIvanov · Pull Request #32 · joomcode/errorx · GitHub
Nothing Special   »   [go: up one dir, main page]

Skip to content

Conversation

PeterIvanov
Copy link
Collaborator
@PeterIvanov PeterIvanov commented Feb 18, 2021

As tests show, errors.Unwrap and errors.Is work exactly as intended and preserve all existing errorx contracts.
On the other hand, errors.As is broken for errorx. It is not a regression of this PR, some tests are added for cases that work, issue will be addressed further in future PRs.

@PeterIvanov PeterIvanov changed the base branch from master to unstable_master February 18, 2021 08:30
@PeterIvanov PeterIvanov requested review from g7r and isopov February 18, 2021 08:36
@PeterIvanov
Copy link
Collaborator Author

Cc @pacejackson

@PeterIvanov PeterIvanov changed the base branch from unstable_master to master February 18, 2021 08:53
@PeterIvanov
Copy link
Collaborator Author

Travis tests are not run for some reason.
https://travis-ci.com/github/joomcode/errorx/requests

Copy link
Contributor
@isopov isopov left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

error_113.go Outdated

// todo add errorx.As()?
// todo make another 'go error type' for passing into errors.As()?
// todo when fixed, add tests for wrap/decorate etc.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't really see the problem with As. Let's remember the use case of errors.As:

// errors.As is designed to replace the following error drilling pattern:
if exitErr, ok := err.(*exec.ExitError); ok && exitErr.ExitCode() == 42 {
    // handle error code 42
}

When you don't need actual error value buried deep in an error chain, errors.Is would suffice.

When you do actually need that, let's remember that all errorx.Error properties are being propagated to topmost error. And that topmost errorx.Error is really what you need because there is no other way to attach additional information to error other than carried by properties.

Therefore, I suggest that errorx.Error shouldn't implement As method.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I suggest you copy this comment to the next PR I sent, and I'll remove this part of change from current PR.

@PeterIvanov PeterIvanov changed the base branch from master to unstable_master February 18, 2021 13:31
@g7r
Copy link
Contributor
g7r commented Feb 18, 2021

I think we're trying to solve wrong problem here. errorx has its own means for checking error type. It is different from errors.Is and errors.As. The problem is that it is difficult to extract errorx error wrapped by third party type and it is difficult to extract third party type wrapped by errorx error.

What we really want is:

  1. errorx.IsOfType should be working no matter how *errorx.Error was wrapped. We already have tools to check errorx error type. We don't need to invent clever wrappers to use with errors.Is and errors.As. That is:
err := fmt.Errorf("wrapped: %w", errorx.IllegalState.NewWithNoMessage())
require.True(t, errorx.IsOfType(err, errorx.IllegalState))
  1. errors.Is and errors.As should be working for third party types after wrapping by errorx. That is:
err := errorx.Decorate(context.Canceled, "fancy decoration")
require.True(t, errors.Is(err, context.Canceled))

@PeterIvanov
Copy link
Collaborator Author
PeterIvanov commented Feb 19, 2021

Let's dissect those arguments a bit.
First, I agree that both of these cases are valid and must be addressed. The second one is covered by this PR already, the first one is not, I would suggest a separate PR for that after we finish with this one.
I disagree that there's a conflict of "wrong problem" here. In my opinion, both are valid problems, and if there's a reasonable and sane way to address both, the result would be better than a more timid solution.

At this point, as I see it, we must choose whether to have a solution that solves only the case shown above, or a wider range of scenarios. The former must be supported by the argument as to what harm does those additions bring.

Historically, similar concepts in errorx predate go 1.13 error features, and the design is based on logical types 8000 , but the idea behind it is very similar. Now, especially after an errorx release with official 1.13 support is made, it would be reasonable to expect that constructs like errors.Is works natively for errorx types. An absence of such support would mean that any errorx user is forced to use strictly errorx syntax for such checks for no obvious good reason, and that package godoc would have to try and make an argument as to why this reason is, indeed, good. Such argument is yet to be presented.

The second argument here is that optional interface{ Is(error) bool } looks to me like something designed to do precisely what is being done here. errors package is quite shy in explaining the intended and unintended use, but I've failed to find anything there that discourages such behaviour and there are parts that seem to agree with it.

Is unwraps its first argument sequentially looking for an error that matches the second

An error type might provide an Is method so it can be treated as equivalent to an existing error

So, it seems to me that making a check in code like

// err is errorx.IllegalArgument
if errors.Is(err, errorx.TimeoutElapsed.NewWithNoMessage()) {
  // try again later
}

return true on any errorx type is not only a lost opportunity, it is a potential for bugs that are hard to track, as we all know that negative cases are often neglected in tests.

The only argument I can find not to do this is in having several ways of doing the same thing, which may be confusing. Currently, godoc aims to help with this, it can be enhanced further. Possibly this is in argument in favour of deprecation and then removal of some of errorx existing API, but I'm not sure the confusion is big enough to justify the breaking change.

@PeterIvanov PeterIvanov requested a review from g7r February 19, 2021 11:57
type.go Outdated
// The original error will not pass its dynamic properties, and those are accessible only via direct walk over Cause() chain.
// Without args, leaves the original message intact, so a message may be generated or provided externally.
// With args, a formatting is performed, and it is therefore expected a format string to be constant.
// NB: Wrap is NOT the reverse of Error.Unwrap method; name may be changed in future releases to avoid confusion.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe we should refer to errors.Unwrap instead of Error.Unwrap?

8000

t.Run("Wrap", func(t *testing.T) {
err := testTypeBar1.Wrap(testType.NewWithNoMessage(), "")
unwrapped := errors.Unwrap(err)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is where unrelatedness between Wrap and Unwrap hits particularly hard :(

err := Decorate(testType.NewWithNoMessage(), "")
unwrapped := errors.Unwrap(err)
require.NotNil(t, unwrapped)
require.True(t, IsOfType(unwrapped, testType))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Technically, unwrapped may be the same as err and the assertions will still pass.

err := Decorate(io.EOF, "")
unwrapped := errors.Unwrap(err)
require.NotNil(t, unwrapped)
require.True(t, errors.Is(unwrapped, io.EOF))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This will be true even if errors.Unwrap returned original err.

})

t.Run("Wrap", func(t *testing.T) {
err := testTypeBar1.Wrap(testType.NewWithNoMessage(),"")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Lack of gofmt detect I.

t.Run("DecorateForeign", func(t *testing.T) {
err := Decorate(io.EOF,"")
require.True(t, errors.Is(err, io.EOF))
})
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should add a test that errorx.IsOfType(err, errorType) penetrates fmt.Errorf("blabla: %w", errorType.NewWithNoMessage()).

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As of this PR, it doesn't. I intend to add both feature and tests in a separate PR.

@PeterIvanov PeterIvanov requested a review from g7r February 23, 2021 08:15
@PeterIvanov PeterIvanov merged commit c749e95 into unstable_master Feb 24, 2021
@PeterIvanov PeterIvanov deleted the feature/1.13_errors branch February 25, 2021 13:57
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet
49B2

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants

0