On Wed, 9 Oct 2024 at 09:54, Ken Lee <ken.lee.kiany...@gmail.com> wrote:

> So can I say that, if I'm not writing concurrency code, it's acceptable
> for me to mix pointer and value receiver?
>

Note that you can't really know, if your users use concurrency or not. And
I still maintain, that concurrency is - mostly - a red herring. Yes,
calling a method with value receiver is a copy and hence a read, so it is a
data race when done concurrently with a write. But there are many possible
ways to read or write to a variable.

I still stand by the point that there is no epidemic of data races on
time.Time.UnmarshalJSON calls, in practice. So obviously, there *are* ways
to mix receiver kinds that does not practically incur this risk of races. I
also think, it is a good example to look at how that works: time.Time is
*in general* used and passed as a value, so over its normal life, it is
never concurrently read/written too - it's mostly read-only. Only in
limited circumstances, related to its initial population is it really
written to - and those are the calls with pointer receivers. And the same
is true for the Enum example I linked: It implements flag.Value and
essentially, it is accessed via pointer during flag parsing, but after that
used as a value. So make the `Set` method a pointer receiver and anything
else a value receiver.

It's a more fuzzy lesson, but I think it's more accurate than talking about
concurrency.


> I find that like what @Axel said, I think there's some struct in STD Lib
> doing this too? case in point, Time struct in "time" package.
>

> On Tuesday 8 October 2024 at 10:29:09 pm UTC+8 Robert Engels wrote:
>
>> And when I provided data and reasoning from “the other side of the table”
>> including code samples, you responded with “Meanwhile, you seem to be
>> aggressively ignoring what I actually wrote. I find that pretty rude.”
>>
>> You need to learn the concept of “in addition to” or “agree, but this is
>> more important” and lose your penchant to immediately rudely escalate the
>> discussion with direct or veiled name calling.
>>
>> On Oct 8, 2024, at 1:37 AM, 'Axel Wagner' via golang-nuts <
>> golan...@googlegroups.com> wrote:
>>
>> 
>>
>> Just to clarify: From what I can tell, I am (in this revival of the
>> thread) the only one on the "mixing receiver kinds is sometimes necessary,
>> so we shouldn't caution against it" side of the table and indeed opened it.
>> As such, I'm already on the back foot. I tried to at least acknowledge the
>> arguments from the other side, even if I don't have much to say about them.
>> I don't believe it's rude to ask for the same from the other side of the
>> table.
>>
>> I don't expect anyone to be invested in convincing me, as a person. But
>> (again, from what I can tell) I represent a side of the discussion here.
>> And it's not possible to have a discussion where one side is simply ignored.
>>
>> On Tue, 8 Oct 2024 at 07:02, Robert Engels <ren...@ix.netcom.com> wrote:
>>
>>> And if you don’t recognize the ass clown rudeness in a statement like “
>>> No offence, but I made an argument. You don't have to agree with the
>>> argument and it might be wrong. But to convince me, at least, that argument
>>> would need to actually be referenced.” you are a narcissistic ahole.
>>>
>>> On Oct 7, 2024, at 11:20 PM, Axel Wagner <axel.wa...@googlemail.com>
>>> wrote:
>>>
>>> 
>>> You are trying to prove something nobody actually doubted. Meanwhile,
>>> you seem to be aggressively ignoring what I actually wrote. I find that
>>> pretty rude.
>>>
>>> On Tue, 8 Oct 2024 at 01:15, robert engels <ren...@ix.netcom.com> wrote:
>>>
>>>> Here is a slightly easier version to see the race between the mutation
>>>> and the copy for the value method:
>>>>
>>>> package main
>>>>
>>>> import (
>>>>     "log"
>>>>     "sync"
>>>> )
>>>>
>>>> type S struct {
>>>>     lock *sync.Mutex
>>>>     index int
>>>>     values [128]int
>>>> }
>>>>
>>>> func (s *S) mutate() {
>>>>     s.lock.Lock();
>>>>     defer s.lock.Unlock();
>>>>     s.index++;
>>>>     for i:=0; i< 128; i++ {
>>>>         s.values[i]=s.index;
>>>>     }
>>>> }
>>>>
>>>> func (s S) validate() {
>>>>     for i:=0;i<128;i++ {
>>>>         if s.values[i]!=s.index {
>>>>             log.Fatal("mismatch error")
>>>>         }
>>>>     }
>>>> }
>>>>
>>>> func doit(s *S) {
>>>>     for {
>>>>         s.mutate()
>>>>         s.validate()
>>>>     }
>>>> }
>>>>
>>>> func main() {
>>>>     var s S
>>>>     var lock sync.Mutex
>>>>     s.lock = &lock
>>>>     var wg sync.WaitGroup
>>>>     wg.Add(1)
>>>>     for i:=0;i<64;i++ {
>>>>         go doit(&s)
>>>>     }
>>>>     wg.Wait()
>>>> }
>>>>
>>>>
>>>> On Oct 7, 2024, at 6:06 PM, robert engels <ren...@ix.netcom.com> wrote:
>>>>
>>>> I wrote a simple test. Sure enough it fails, and it reports a data race.
>>>>
>>>> package main
>>>>
>>>> import (
>>>>     "log"
>>>>     "sync"
>>>> )
>>>>
>>>> type S struct {
>>>>     sync.Mutex
>>>>     index int
>>>>     values [128]int
>>>> }
>>>>
>>>> func (s *S) mutate() {
>>>>     s.Lock();
>>>>     defer s.Unlock();
>>>>     s.index++;
>>>>     for i:=0; i< 128; i++ {
>>>>         s.values[i]=s.index;
>>>>     }
>>>> }
>>>>
>>>> func (s S) validate() {
>>>>     for i:=0;i<128;i++ {
>>>>         if s.values[i]!=s.index {
>>>>             log.Fatal("mismatch error")
>>>>         }
>>>>     }
>>>> }
>>>>
>>>> func doit(s *S) {
>>>>     for {
>>>>         s.mutate()
>>>>         s.validate()
>>>>     }
>>>> }
>>>>
>>>> func main() {
>>>>     var s S
>>>>     var wg sync.WaitGroup
>>>>     wg.Add(1)
>>>>     for i:=0;i<64;i++ {
>>>>         go doit(&s)
>>>>     }
>>>>     wg.Wait()
>>>> }
>>>>
>>>> In fact, you get a linter warning, because of the copy of the mutex in
>>>> calling the value method - since it knows it should be a reference.
>>>>
>>>>
>>>> On Oct 7, 2024, at 5:30 PM, Robert Engels <ren...@ix.netcom.com> wrote:
>>>>
>>>> I am fairly certain if you mix pointer and receiver methods and the
>>>> receiver methods mutate - even if you synchronize those you will get a data
>>>> race calling the value methods. It must afaik as the runtime/compiler has
>>>> no implicit synchronization when creating the copies. That is a data race.
>>>>
>>>> On Oct 7, 2024, at 5:10 PM, Axel Wagner <axel.wa...@googlemail.com>
>>>> wrote:
>>>>
>>>> 
>>>> My argument had nothing to do with synchronization.
>>>>
>>>> FTR I find the synchronization argument also extremely dubious. By that
>>>> argument, you also can't pass the address to a local variable to another
>>>> function, when using it as a value elsewhere. It's a weird argument to
>>>> make. time.Time uses a mix of pointer- and value receivers and IMO no one
>>>> can make a serious argument that this would expose programs to risks of
>>>> data races.
>>>>
>>>> But to repeat my actual argument in favour of (sometimes) mixing
>>>> receiver kinds:
>>>> 1. It is totally reasonable to use some types as values.
>>>> 2. Such types, intended to be used as values, will need to use
>>>> value-receivers for some methods, as otherwise their value-version does not
>>>> implement certain interfaces (methods are not promoted from pointer to
>>>> value types). Like fmt.Stringer, for example. And
>>>> 3. such types still need to sometimes use pointer-receivers, to
>>>> implement functionalities like unmarshalling.
>>>>
>>>> time.Time is a standard library example of such a type. I also provided
>>>> an example for an "enum-like" type implementing flag.Value.
>>>>
>>>> On Mon, 7 Oct 2024 at 23:57, Robert Engels <ren...@ix.netcom.com>
>>>> wrote:
>>>>
>>>>> I am pretty sure it is immaterial. If the object isn’t immutable any
>>>>> copy or mutation operation needs to be synchronized.
>>>>>
>>>>> But the problem afaik is that you can’t control synchronization when
>>>>> the object is copied for a value receiver - which means you cant properly
>>>>> synchronize when you have pointer and value receivers unless you do it
>>>>> externally (which is a huge pain to do everywhere).
>>>>>
>>>>> On Oct 7, 2024, at 4:43 PM, 'Axel Wagner' via golang-nuts <
>>>>> golan...@googlegroups.com> wrote:
>>>>>
>>>>> 
>>>>> No offence, but I made an argument. You don't have to agree with the
>>>>> argument and it might be wrong. But to convince me, at least, that 
>>>>> argument
>>>>> would need to actually be referenced.
>>>>>
>>>>> I gave reasons why, in my opinion, *not* mixing value and pointer
>>>>> receivers sometimes leads to incorrect code. So as far as I'm concerned
>>>>> (until someone tells me my reasons are wrong) Goland's linter simply
>>>>> encourages you to write bad code. It would not be the first time that I
>>>>> strongly disagree with the recommendations of an IDE. Goland in particular
>>>>> has a history of making, in my opinion, pretty questionable decisions.
>>>>>
>>>>> On Mon, 7 Oct 2024 at 22:39, Cleberson Pedreira Pauluci <
>>>>> pauluci....@gmail.com> wrote:
>>>>>
>>>>>> Many places and books I've read generally say: If a function needs to
>>>>>> update a variable, or if an argument is so large that we want to avoid
>>>>>> copying it, we should pass the pointer. Same for methods (pointer
>>>>>> receiver). (The Go programming language book).
>>>>>>
>>>>>> About mixing "value receiver" and "pointer receiver". Even the IDE
>>>>>> complains about this and recommends following the Go documentation. 
>>>>>> (Goland)
>>>>>>
>>>>>>
>>>>>> Em segunda-feira, 7 de outubro de 2024 às 15:15:25 UTC-3, burak
>>>>>> serdar escreveu:
>>>>>>
>>>>>>> Mixing pointer and value receivers can be race-prone, because of the
>>>>>>> copying involved in passing value receivers.
>>>>>>>
>>>>>>> On Mon, Oct 7, 2024 at 12:03 PM 'Axel Wagner' via golang-nuts
>>>>>>> <golan...@googlegroups.com> wrote:
>>>>>>> >
>>>>>>> > To be honest, I always found this recommendation a little bit
>>>>>>> strange, personally.
>>>>>>> >
>>>>>>> > I'll note that the standard library does not really keep to this
>>>>>>> either. For example, time.Time.UnmarshalText (obviously) has a
>>>>>>> pointer-receiver, while almost all other methods on time.Time have a 
>>>>>>> value
>>>>>>> receiver.
>>>>>>> > And if you implement flag.Value, the Set method obviously needs a
>>>>>>> pointer receiver, but if the String method has one as well, it won't 
>>>>>>> print
>>>>>>> properly when used as a value. In basically every implementation of
>>>>>>> flag.Value I've ever written, String needed a value receiver, while Set
>>>>>>> needed a pointer receiver.
>>>>>>> >
>>>>>>> > I understand the basic idea of the advice, that if a type keeps
>>>>>>> state that is manipulated via methods, then it should generally be 
>>>>>>> passed
>>>>>>> around as a pointer, so giving all the methods a pointer-receiver works
>>>>>>> well. But if a type *is* intended to be used as a value (like time.Time 
>>>>>>> or
>>>>>>> Enum in my example) then you will almost certainly end up with a mix of
>>>>>>> receiver kinds - as soon as you want to add any form of 
>>>>>>> de-serialization to
>>>>>>> it. So "don't mix receiver kinds" seems like misleading advice to me.
>>>>>>> >
>>>>>>> > On Mon, 7 Oct 2024 at 19:44, Ian Lance Taylor <ia...@golang.org>
>>>>>>> wrote:
>>>>>>> >>
>>>>>>> >> On Mon, Oct 7, 2024 at 10:29 AM Ken Lee <ken.lee....@gmail.com>
>>>>>>> wrote:
>>>>>>> >> >
>>>>>>> >> > ---
>>>>>>> >> > There is a consideration to make, though: historically it has
>>>>>>> been considered bad form in Go to give a type a mix of value and pointer
>>>>>>> receivers in methods without a very specific reason for doing so.
>>>>>>> >> > ---
>>>>>>> >> >
>>>>>>> >> > Is this still the case now? As in 2024.
>>>>>>> >>
>>>>>>> >> As a general guideline, yes.
>>>>>>> >>
>>>>>>> >> https://go.dev/wiki/CodeReviewComments#receiver-type
>>>>>>> >>
>>>>>>> >> Ian
>>>>>>> >>
>>>>>>> >>
>>>>>>> >>
>>>>>>> >> > On Sunday 13 January 2013 at 7:03:29 am UTC+8 Kevin Gillette
>>>>>>> wrote:
>>>>>>> >> >>
>>>>>>> >> >> Indeed. In addition to implicit dereferencing for value
>>>>>>> receivers, the reverse also works as well: anything that is addressable
>>>>>>> (including 'value' variables on the stack, or a field of element of
>>>>>>> anything that's addressable) will implicitly be addressed when a
>>>>>>> pointer-receiver method is called on them (though you must explicitly 
>>>>>>> use
>>>>>>> the address operator when you need to pass value variables as pointers).
>>>>>>> >> >>
>>>>>>> >> >> There is a consideration to make, though: historically it has
>>>>>>> been considered bad form in Go to give a type a mix of value and pointer
>>>>>>> receivers in methods without a very specific reason for doing so. The
>>>>>>> typical justification is that a small struct in a getter method might as
>>>>>>> well have a value receiver even though the corresponding setter method 
>>>>>>> uses
>>>>>>> a pointer receiver; this, however, can lead to confusion on the part of 
>>>>>>> the
>>>>>>> app programmer if they start out using only the read-only methods upon 
>>>>>>> what
>>>>>>> turns out to be a value-copy of the original (but hey, it compiled and
>>>>>>> seems to work, so it must be correct) -- when use of pointer-receiver
>>>>>>> methods don't seem to produce the documented changes in the original, it
>>>>>>> can be difficult to debug.
>>>>>>> >> >>
>>>>>>> >> >>
>>>>>>> >> >> On Saturday, January 12, 2013 3:17:16 PM UTC-7, Dave Collins
>>>>>>> wrote:
>>>>>>> >> >>>
>>>>>>> >> >>> On Saturday, January 12, 2013 3:52:35 PM UTC-6, Taric Mirza
>>>>>>> wrote:
>>>>>>> >> >>>>
>>>>>>> >> >>>> Thanks! Works like a charm and is helping cleaning up my
>>>>>>> code a ton.
>>>>>>> >> >>>>
>>>>>>> >> >>>> One other question, this is really more about coding style:
>>>>>>> >> >>>>
>>>>>>> >> >>>> In the case where you manipulate members of the struct, then
>>>>>>> using
>>>>>>> >> >>>> pointers as in your example is the way to go.
>>>>>>> >> >>>>
>>>>>>> >> >>>> But, you have a choice for functions that just read values
>>>>>>> from the
>>>>>>> >> >>>> struct instead of manipulating it. Is there a best practice
>>>>>>> coding
>>>>>>> >> >>>> style here, between dereferencing the struct and then using
>>>>>>> that, or
>>>>>>> >> >>>> dereferencing each member of the struct as you go? eg:
>>>>>>> >> >>>>
>>>>>>> >> >>>> // A:
>>>>>>> >> >>>>
>>>>>>> >> >>>> laser := worldobj.(*Laser)
>>>>>>> >> >>>> fmt.Printf("%0.4f,%0.4f", (*laser).x, (*laser).y)
>>>>>>> >> >>>>
>>>>>>> >> >>>> versus
>>>>>>> >> >>>>
>>>>>>> >> >>>> // B:
>>>>>>> >> >>>>
>>>>>>> >> >>>> laser := *(worldobj.(*Laser))
>>>>>>> >> >>>> fmt.Printf("%0.4f,%0.4f", laser.x, laser.y)
>>>>>>> >> >>>>
>>>>>>> >> >>>>
>>>>>>> >> >>>> I'm kind of torn. I would imagine A) has slightly better
>>>>>>> >> >>>> performance, and doesn't require any code-rework if you
>>>>>>> later on need
>>>>>>> >> >>>> to manipulate the struct.
>>>>>>> >> >>>>
>>>>>>> >> >>>> On the other hand, B) is more readable since you don't have
>>>>>>> to look at
>>>>>>> >> >>>> pointers all over the place, just on one line.
>>>>>>> >> >>>
>>>>>>> >> >>>
>>>>>>> >> >>> Actually, you don't need to dereference at all. Go
>>>>>>> automatically handles this for you.
>>>>>>> >> >>>
>>>>>>> >> >>> See this example: http://play.golang.org/p/ANaKaFSQLn
>>>>>>> >> >>>
>>>>>>> >> > --
>>>>>>> >> > 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 on the web visit
>>>>>>> https://groups.google.com/d/msgid/golang-nuts/03df7dce-5c48-44a3-bc3c-851ded2a1f08n%40googlegroups.com.
>>>>>>>
>>>>>>> >>
>>>>>>> >> --
>>>>>>> >> 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 on the web visit
>>>>>>> https://groups.google.com/d/msgid/golang-nuts/CAOyqgcX7v9Edk5beRH38tfJO18ZUXv-nOHsEPPCfMQy0hz%3DFdw%40mail.gmail.com.
>>>>>>>
>>>>>>> >
>>>>>>> > --
>>>>>>> > 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 on the web visit
>>>>>>> https://groups.google.com/d/msgid/golang-nuts/CAEkBMfGcq2nxaik_qAWoX81W-tTKRRYBDM5_6%3DefSv4tr8b03g%40mail.gmail.com.
>>>>>>>
>>>>>>>
>>>>>>
>>>>>> --
>>>>>> 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 on the web visit
>>>>>> https://groups.google.com/d/msgid/golang-nuts/9b28006b-c310-417e-9afc-e7f5c470641cn%40googlegroups.com
>>>>>> <https://groups.google.com/d/msgid/golang-nuts/9b28006b-c310-417e-9afc-e7f5c470641cn%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...@googlegroups.com.
>>>>> To view this discussion on the web visit
>>>>> https://groups.google.com/d/msgid/golang-nuts/CAEkBMfEj%3DQACB31VMc7ami7xt9tMF00kYxFUfZpWfZ0j65GWsw%40mail.gmail.com
>>>>> <https://groups.google.com/d/msgid/golang-nuts/CAEkBMfEj%3DQACB31VMc7ami7xt9tMF00kYxFUfZpWfZ0j65GWsw%40mail.gmail.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...@googlegroups.com.
>>>> To view this discussion on the web visit
>>>> https://groups.google.com/d/msgid/golang-nuts/CAEkBMfFYZ1DTD9fTVzNHtOp7Ed7w3_x8QbxsB2x_%2BTs%3DtxY0BA%40mail.gmail.com
>>>> <https://groups.google.com/d/msgid/golang-nuts/CAEkBMfFYZ1DTD9fTVzNHtOp7Ed7w3_x8QbxsB2x_%2BTs%3DtxY0BA%40mail.gmail.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...@googlegroups.com.
>>>> To view this discussion on the web visit
>>>> https://groups.google.com/d/msgid/golang-nuts/B6F948A5-9F2E-4698-85D1-17B862779901%40ix.netcom.com
>>>> <https://groups.google.com/d/msgid/golang-nuts/B6F948A5-9F2E-4698-85D1-17B862779901%40ix.netcom.com?utm_medium=email&utm_source=footer>
>>>> .
>>>>
>>>>
>>>>
>>>> --
>>
>> You received this message because you are subscribed to a topic in the
>> Google Groups "golang-nuts" group.
>> To unsubscribe from this topic, visit
>> https://groups.google.com/d/topic/golang-nuts/_MEf-I49OTo/unsubscribe.
>> To unsubscribe from this group and all its topics, send an email to
>> golang-nuts...@googlegroups.com.
>> To view this discussion on the web visit
>> https://groups.google.com/d/msgid/golang-nuts/CAEkBMfGb7xEu%3Da73xWUBuAGK2T3_R7uA4K5FZYr4vYzkLpTxqg%40mail.gmail.com
>> <https://groups.google.com/d/msgid/golang-nuts/CAEkBMfGb7xEu%3Da73xWUBuAGK2T3_R7uA4K5FZYr4vYzkLpTxqg%40mail.gmail.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 on the web visit
> https://groups.google.com/d/msgid/golang-nuts/0f008c03-200a-4fa5-8198-3b1f0a227f9cn%40googlegroups.com
> <https://groups.google.com/d/msgid/golang-nuts/0f008c03-200a-4fa5-8198-3b1f0a227f9cn%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 on the web visit 
https://groups.google.com/d/msgid/golang-nuts/CAEkBMfE5gDYrCDrM4T%3DFh%3DoE1d7xFkP3SNXQdPyLZCfYR_2c3Q%40mail.gmail.com.

Reply via email to