It's also consistent with the common idiom of errors.New("foo") which returns a pointer (to an unexported type) - although this doesn't appear to be documented, except that "Each call to New returns a distinct error value even if the text is identical"
On Wednesday, 12 February 2025 at 09:06:08 UTC Axel Wagner wrote: > On Wed, 12 Feb 2025 at 09:21, cpu...@gmail.com <cpu...@gmail.com> wrote: > >> I've had some ongoing confusion about using errors.As (see >> https://play.golang.com/p/m4_cXCzOViD). The issue I'm having is this >> part of the contract: >> >> > An error matches target if the error's concrete value is assignable to >> the value pointed to by target >> >> I always expected (yes, I know), that base and pointer receivers are >> interchangeable. This is not the case (see playground). This seems to make >> using it error-prone as you'll always need to carefully think about the >> return type of the function invoked. While the contract is always error, a >> function may return a base or a pointer error type. This influences how >> using errors.As must be done. >> >> Are there best practices for: >> - return base vs. pointer errors >> > > The best practice is pointer errors. I would have personally preferred to > live in a world where value errors are better (in particular, it would be > pretty nice to be able to compare full error values using `==` in tests). > But the issue you have discovered is pretty much exactly, why pointer > errors are better. > > If you declare `Error()` on a value receiver, then both `err.(YourErr)` > and `err.(*YourErr)` will compile just fine, as value-methods are promoted > to the pointer type. But only one of them will succeed. Similarly, both > `return YourErr{…}` and `return &YourErr{…}` will compile. So it is > somewhat easy to make a mistake that are then hard to debug in practice - > and the error paths tend to be badly tested already. > > If, on the other hand, you declare it with a pointer receiver, only > `err.(*YourErr)` and `return &YourErr{…}` will compile. Meaning the > compiler ensures that you write the correct code. > > errors.As is ultimately a dynamic extension of this semantic difference, > which is the problem you have stumbled on. > > >> - crafting the errors.As target type without inspecting the actual >> function invoked >> >> ...and could it make sense to lessen errors.As to match pointer with >> non-pointer receivers? >> >> Thanks! >> >> -- >> 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...@googlegroups.com. >> To view this discussion visit >> https://groups.google.com/d/msgid/golang-nuts/afe2df8a-9e42-4511-abe6-8e03b906d637n%40googlegroups.com >> >> <https://groups.google.com/d/msgid/golang-nuts/afe2df8a-9e42-4511-abe6-8e03b906d637n%40googlegroups.com?utm_medium=email&utm_source=footer> >> . >> > -- 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 visit https://groups.google.com/d/msgid/golang-nuts/98375669-c29b-4d06-bf79-04c548aada46n%40googlegroups.com.