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, [email protected] <[email protected]> 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 [email protected].
>> 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 [email protected].
To view this discussion visit
https://groups.google.com/d/msgid/golang-nuts/98375669-c29b-4d06-bf79-04c548aada46n%40googlegroups.com.