That's a really good question, IMO.

I have been wondering for a while why the advice against mixing pointer and 
value receivers, which GoLang so often flags me for doing. 

Ideally I think that I would like to be able use value receivers most of 
the time when I want the method to leave the state unmodified, and only use 
pointer receivers when I want state to be modified.  And, I don't want to 
have to ignore GoLand's warnings or have a CI/CD linter warn me about it 
considering that I want to do it on purpose.  I could turn off the warning 
in GoLand, but that doesn't change coding standards on teams I might work 
on who religiously follow the Go team's recommendations.

Given this thread I finally did some research. Tracking it down in the Go 
FAQ <https://go.dev/doc/faq#methods_on_values_or_pointers> it says:


*> Next is consistency. If some of the methods of the type must have 
pointer receivers, the rest should too, so the method set is consistent 
regardless of how the type is used. See the section on method sets 
<https://go.dev/doc/faq#different_method_sets> for details. *
Tracking down method sets it says *(abridged):*

> *the method set of a type T consists of all methods with receiver type T, 
while that of the corresponding pointer type *T consists of all methods 
with receiver *T or T. That means the method set of *T includes that of T, 
but not the reverse.*
*> This distinction arises because if an interface value contains a pointer 
*T, a method call can obtain a value by dereferencing the pointer, but if 
an interface value contains a value T, there is no safe way for a method 
call to obtain a pointer. (Doing so would allow a method to modify the 
contents of the value inside the interface, which is not permitted ...)*
*> Even in cases where the compiler could take the address of a value to 
pass to the method, if the method modifies the value the changes will be 
lost in the caller. ... This is almost never the desired behavior.*

I decided to so some experimentation and turns out it a compile error 
occurs when a value variable is used with a pointer receiver:  

- https://goplay.tools/snippet/_AiFRsc9w-r

There are six (6) permutations of an interface and the variable of the 
interface type, two (2) of which will not compile:

1. A value variable and multiple value receivers  <--- compiles
2. A pointer variable and multiple value receivers <--- compiles
3. A pointer variable and multiple pointer receivers.  <--- compiles 
4. A value variable and multiple pointer receivers.  <--- will NOT compile
5. A pointer variable and mixed value+pointer receivers  <--- compiles 
6. A value variable and mixed value+pointer receivers. <--- will NOT compile

Permutation #4 and #6 are consistent with the description above, and they 
both have *a value variable *in common.

However, given than #5 DOES compile, I was left wondering why the standard 
that mixed receivers should be flagged as an error? 

I ask rhetorically — or better yet, to the Go team — shouldn't mixed 
receivers be considered acceptable, especially when they would allows 
ensuring the receiver is not changed by the method that should not change 
it? And then shouldn't the guidance in the FAQ be to use *value* receivers 
unless the receiver needs to be modified within the method?

I do get that changing the guidance could violate the conceptual purity of 
the *"method set <https://go.dev/doc/faq#different_method_sets>"* 
definition, but pragmatically is being able to mix receiver types not more 
useful in practice?  If the developer makes a mistake and passes a 
non-pointer interface value to a method with a pointer receiver they will 
get a compile error, so there does not appear to be any downside for 
changing the recommendation regarding consistency with method receivers?

Or is there something really obvious I am just missing?

-Mike
On Monday, November 13, 2023 at 4:49:56 PM UTC-5 Brad Johnson wrote:

> Google's style guide is a popular reference for Go programmers. In it, 
> they list off a number of scenarios where one would use a value receiver vs 
> a pointer receiver. But, ultimately, they end the list with "when in doubt, 
> use a pointer receiver".
>
> In my experience, I've noticed the majority of Go programmers I encounter 
> default to using pointer receivers in all circumstances. And I have a hard 
> time justifying any protest because the scenarios typically don't fall into 
> the "approved" set where value receivers are recommended.
>
> I also notice that my IDE (GoLand) defaults to returning a pointer to a 
> struct when I use its "Generate Constructor" auto-complete functionality. I 
> can't help but suspect this was motivated by the "when in doubt" advice 
> from Google.
>
> I'd be curious to hear thoughts on this topic. I tend to advise developers 
> to default to value receivers because I perceive benefits to avoiding nil 
> pointer exceptions. But it's hard to substantiate my advice as anything 
> idiomatic.
>

-- 
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/3aadebb4-68ef-43ed-8c10-d7531fb576f6n%40googlegroups.com.

Reply via email to