One more try : ) > 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. >
That the receiver always act as a ref to a value stored /wherever/ That only the consumer decides where that value is stored using pointer/not., unless the declarer installed a barrier. On Thursday, May 11, 2017 at 1:10:21 PM UTC+2, Chris Hopkins wrote: > > 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. > same as today with pointer no ? > 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? > > if foo is not referencable, then the method DoUsefulStuff() necessarily provides an out param such DoUsefulStuff() <myself> That you did not copied back the returned value in your scope is already an error today. > 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 > I dont get it, to return a corrupted state shall we not use an extra error parameter? Still, that situation will apply if you use pointer. 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. > because you focus on the type definition to lookup for possible suspects. yes i argue its all about var definition and func in params. yes it looks like they way i think multiply the place of errors. > > 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 > > I sincerely thanks everyone on the thread, not easy task. After all, Happy we kindly disagree :) 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.