Hi all,

I found an error that instantiate with type that have field cannot be
compared with the instance of the same type.  Here is the test code,

----
        type typeErrorWithoutField struct{}

        func (te *typeErrorWithoutField) Error() string {
                return "typeError"
        }

        type typeErrorWithPublicField struct {
                P string
        }

        func (te *typeErrorWithPublicField) Error() string {
                return "typeErrorWithPublicField"
        }

        type typeErrorWithPrivateField struct {
                p string
        }

        func (te *typeErrorWithPrivateField) Error() string {
                return "typeErrorWithPrivateField"
        }

        type typeErrorWithIs struct {
                p string
        }

        func (te *typeErrorWithIs) Error() string {
                return "typeErrorWithIs"
        }

        func (te *typeErrorWithIs) Is(target error) bool {
                return target.Error() == te.Error()
        }

        func TestErrors(t *testing.T) {
                cases := []struct {
                        desc   string
                        err    error
                        target error
                }{{
                        err:    &typeErrorWithoutField{},
                        target: &typeErrorWithoutField{},
                }, {
                        desc:   "With error created from 
&typeErrorWithPublicField{}",
                        err:    &typeErrorWithPublicField{},
                        target: &typeErrorWithPublicField{},
                }, {
                        desc:   "With error created from 
&typeErrorWithPrivateField{}",
                        err:    &typeErrorWithPrivateField{},
                        target: &typeErrorWithPrivateField{},
                }, {
                        desc:   "With error created from &typeErrorWithIs{}",
                        err:    &typeErrorWithIs{},
                        target: &typeErrorWithIs{},
                }}

                for _, c := range cases {
                        t.Log(c.desc)
                        t.Logf("err == target: %v\n", c.err == c.target)
                        t.Logf("errors.Is(err, target): %v\n", errors.Is(c.err, 
c.target))
                }
        }
----

Running this on Go tip, Go 1.16.3, Go 1.15.11 return the same output,

----
         ms@inspiro 0 % go test -v -count=1 .
        === RUN   TestErrors
            errors_test.go:69:
            errors_test.go:70: err == target: true
            errors_test.go:71: errors.Is(err, target): true
            errors_test.go:69: With error created from 
&typeErrorWithPublicField{}
            errors_test.go:70: err == target: false
            errors_test.go:71: errors.Is(err, target): false
            errors_test.go:69: With error created from 
&typeErrorWithPrivateField{}
            errors_test.go:70: err == target: false
            errors_test.go:71: errors.Is(err, target): false
            errors_test.go:69: With error created from &typeErrorWithIs{}
            errors_test.go:70: err == target: false
            errors_test.go:71: errors.Is(err, target): true
        --- PASS: TestErrors (0.00s)
        === RUN   TestTypeErrorWithoutField
            errors_test.go:81: err == target: true
            errors_test.go:82: errors.Is(err, target): true
        --- PASS: TestTypeErrorWithoutField (0.00s)
        === RUN   TestTypeErrorWithPublicField
            errors_test.go:91: err == target: false
            errors_test.go:92: errors.Is(err, target): false
        --- PASS: TestTypeErrorWithPublicField (0.00s)
        === RUN   TestTypeErrorWithIs
            errors_test.go:101: err == target: false
            errors_test.go:102: errors.Is(err, target): true
        --- PASS: TestTypeErrorWithIs (0.00s)
        PASS
        ok      git.sr.ht/~shulhan/sandbox/errors       0.001s
----

The only way to make the error comparable and return true is by
implementing method Is() on the type and use the errors.Is to compare it,
or manually by using err.Error() == obj.Error().

The thing is, 1) there are some error type that does not implement the Is() 
type.
One that I stumbled on is ssh.PassphraseMissingError.
2) some people, like me, assume that errors.Is() working for type defined error,
but in fact it is not.

Did I miss something? Is this a bug or an expected behaviour?

-- 
You received this message because you are subscribed to the Google Groups 
"golang-nuts" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to golang-nuts+unsubscr...@googlegroups.com.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/golang-nuts/20210404201615.77d55e97%40inspiro.shul.localdomain.

Attachment: pgphpNOBDWMku.pgp
Description: OpenPGP digital signature

Reply via email to