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 <reng...@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.wagner...@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 <reng...@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 <reng...@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 <reng...@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.wagner...@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 <reng...@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 < >>> golang-nuts@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.cleber...@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+unsubscr...@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+unsubscr...@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+unsubscr...@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+unsubscr...@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 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/CAEkBMfGb7xEu%3Da73xWUBuAGK2T3_R7uA4K5FZYr4vYzkLpTxqg%40mail.gmail.com.