I think what you're saying is that it's more natural and obvious that when you have a function that changes something it would be more obvious and simple if it actually did modify the thing you gave it. Having to jump through hoops to actually make the change you asked for stick is annoying.
Yes? Is that what you mean? Is this a commentary on the effect this has on ease of code read and writability? What I have come to realise recently by working on ever larger projects is that no that's not annoying. When debugging code I don't understand often half the challenge is working out how a piece of data has changed that shouldn't have been. In the world you describe anything that touched that variable could be to blame for my problems. If instead you have to jump through hoops to make modifications and those modifications are really obvious where they are happening you make debugging easier. Forcing the behaviour that "functions/methods don't modify their associated structures" means people structure their code differently that in my experience means instead of code that reads: foo.DoUsefulStuff(i) // has foo become corrupted? changed, who knows? you instead see code like: fred = foo.Lookup(i) // Complex function that changes nothing in foo foo = foo.ReturnUsefulStuff(fred) // This returns a corrupted structure For a start you look at the function definitions and see quickly that they are not modifying the underlying structures so it's quick to discount a large chunk of code as the a source of the problem. This is not so much of a problem in your examples but in large undocumented projects where you don't understand 99% of the code the small things make it much faster to isolate where things could be going wrong. Please don't take this though as anything other than a commentary on the code I like to read. "Code is written for humans to read and only incidentally for machines to execute". I believe code is read by humans way more times than it is written, so anything at all that isolates the code and makes it easier to understand is worth putting time and effort into. YMMV On Thursday, 11 May 2017 11:39:18 UTC+1, mhh...@gmail.com wrote: > > Hi, > > thanks again! > > I m not the one to validate a perfect answer, > i can simply tell that from my go learning and understanding, > i agree top notch 200% no question there > on this description, > which is weird in fact. > > I d only remark about this, > > so there are actually just two cases: Method is on pointer receiver or > not. > > From the declarer side, > there is indeed only 2 cases, > which accounts for 50% of the whole, > declaration + consumption, > the consumer is still accountable for the remaining > 50% of the instance consumption and usage. > > Does it make it less dead simple ? > > In my example i might have named the method as `whatever`, > still there is an explicit value set on a receiver property. > I don t feel like i have assumed anything from the method name. > > > On Thursday, May 11, 2017 at 12:17:00 PM UTC+2, Volker Dobler wrote: >> >> On Thursday, 11 May 2017 11:28:33 UTC+2, mhh...@gmail.com wrote: >>> >>> //defined >>>> var x &T{} // put on heap >>>> var x T // put on stack >>>> >>>> This is definitely a misconception: Allocation on heap vs stack is >>>> totaly unrelated to value methods vs pointer methods. Both examples >>>> might be allocated on the stack or on the heap and this depends >>>> on other factors than methods of T. >>>> >>> >>> what are other factors ? >>> >> >> Roughly: If the compiler cannot prove that x *can* be safely put on the >> stack then it must go to the heap. Values cannot go safely to the stack >> if they might outlive the scope of this stack frame / the current >> function. >> This can happen if e.g. a pointer to such value leaves the function, e.g. >> in a return or a channel send. Search for escape analysis if you are >> interested in the gory details, but I'd urge you not to until the basic >> stuff >> is total clear. >> >> >>> (let s keep it short, optimized code is not a topic for me) >>> I understood that the next func call (might be method) >>> will decide how the instance (to not say value here) is passed. >>> >>> is it ? >>> >> >> Each and every function --- be it a normal function, a function literal, >> a closure, a method, whatever --- completely determines its arguments. >> This includes the receiver of a method which technical is just a normal >> (the first) function argument. >> A func f(int) is called with an argument of type int and a func g(*int) is >> called with a *int. The same is true for receivers. There is *no* magic >> here! >> >> The only thing "magical" with methods and their special receiver >> argument that the compiler automatically (automagically) takes the >> address of a value or dereferences a pointer to match the method >> signature. That's all. That's convenience only. A bit less typing, a bit >> fewer braces, it reads nicer. >> >> So: Yes, it is. >> >> >>> >>>> What can i do with `func (x *T)...` i can not do with `func (x T)`, >>>>> except checking for T==nil ? >>>>> >>>> >>>> Like explained several times in this thread: >>>> func (x *T) lets you modify *x >>>> >>> >>> yes, i really want not to question >>> the ability to modify a value in place. >>> >>> its really about its form. >>> >>> In this code, >>> starting at 0, >>> is case 1 not an aberration, >>> is case 3 is useless >>> https://play.golang.org/p/VyOfZyt7rw >>> >>> Note case 0 is expected to fail and might be detected. >>> >>> ? >>> >> >> All four cases a perfectly fine and useful. >> The problem here is *not* the language construct but probably >> your prejudice that a method called "SetName" should >> modify the x it is "applied" to in any case as it does e.g. >> in Java where there are no (non-primitive) value types. >> >> Let's use abstract function names and let's add some real >> code (as setters and getter in Go are a bit funny). >> >> type T { s string } >> func (t T) M(s string) { >> if t.s == "" { t.s = "GET" } // default HTTP method used if nothing >> else selected >> foo(t, s) >> } >> >> default := T{} >> default.M("bar") >> post := T{s: "POST"} >> post.M("bar") >> >> Can you see it? M operates on a copy of the value it is invoked >> on. Both default and post will be copied. The copy of default is >> modified and this modification is passed foo. This is nice and >> useful and there is no reason the disallow this type of code. >> >> It is really dead simple: If your methods intend to modify the receiver, >> the receiver must be a pointer. This is one simple rule, clear and >> straightforward, easy to remember and easy to derive in case one >> forgets it. >> >> Again. This all does not depend on what the x in x.M is. it can >> be a pointer or a value, the compiler will take the address or dereference >> as needed, so there are actually just two cases: Method is on >> pointer receiver or not. As I said. Dead simple. >> >> >>> >>> Probably i miss some understanding about why i can do that, >>> - handle value handling in two places of the program >>> - at initialization, at consumption >>> >>> does it help ? >>> >> >> I'm sorry I do not understand the question. >> >> >> V. >> > -- 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. For more options, visit https://groups.google.com/d/optout.