8 ms·
Things I Wish Someone Had Told Me About Go
- jgrahamc 14y agoBut, without pointer arithmetics or, despite many claims, pass-by-reference, Go's "pointers" feels like a more flexible form of Java/Ruby/Python/Node/.... It's not clear from the first example if the writer actually understands pointers. The example code passes a pointer to a function and then modifies the pointer, not what it's pointing to. It was no surprise to me that this wouldn't modify the original thing the pointer was referencing. If they wanted to modify the pointer itself then they should have passed a * * User not a *User. Go does, indeed, have pass-by-reference (use a pointer) or pass-by-value (don't use a pointer).
- deleted 14y ago[deleted]
- latch 14y agoI understand what a pointer is, but it's entirely possible that I still don't grok Go. Before writing that, I did try: func main() { u := &User{Name: "Leto"} Modify(&u) } func Modify(u **User) { u = &User{Name: "Paul"} } With no luck.
- zeeboo 14y agoNope, looks like you don't understand pointers. You're still modifying the passed-by-value pointer to a pointer, and not the thing that it points to.
- GhotiFish 14y agoah! That makes a lot of sense actually. If you want to cause side effects in a function, you have to dereference something. (or call another evil function) The only exception being dot operators, which implicitly dereference their left hand argument. (&x).whatever() == x.whatever() I wish go had used arrow notation now. Explicitly marking side effects is a good thing.
- voidlogic 14y agoIs this what you want? http://play.golang.org/p/Pt1D_ICJu5 http://play.golang.org/p/Pt1D_ICJu5
- latch 14y agoYes. Thank you! I completely admit that I'm wrong. Nevertheless, 1 thing to add. Maybe I'm being pedantic, or maybe I still don't get it, but even Go's FAQ says "everything in Go is passed by value". If you call what Go does pass by reference, what do you call what C#'s "ref" keyword does?
- voidlogic 14y agoBesides the few special built-in types that are passed by reference, everything else if passed by value. (Even "reference types" are actually structs that are passed by value (http://golang.org/pkg/reflect/#SliceHeader http://golang.org/pkg/reflect/#SliceHeader). And not reference types in the sense they are in other languages. For example if you pass a struct, you are passing it by value, but if you pass a pointer to that struct, you are also passing by the argument by value. Why? Because even though the pointer contains a reference to the struct as its value, the pointer itself (which is the same as any other integer datatype to the computer) is being passed by value. If your not familiar with pointers and C and languages with reference values like C++/Java this distinction isn't going to mean much to you however.
- NateDad 14y agoYeah, I wish they hadn't called them "Reference types" - I think it's confusing. They're just value types that happen to have a small value and a pointer to the bigger data.
- voidlogic 14y agoI would agree with that sentiment. I would have called them "auto-alias types" maybe or "auto-clone types"?
- 14y ago
- fmstephe 14y agoEnjoyed your article. I think that you are a little off the mark with respect to pointers though. The simple solution to your first example is to simply write to the Name field of the struct being pointed too. http://play.golang.org/p/D3t0Iv8oG4 http://play.golang.org/p/D3t0Iv8oG4 If you want to do complex pointer meddling (and replace the entire struct) you need this syntax. http://play.golang.org/p/tMwHC-k-bu http://play.golang.org/p/tMwHC-k-bu As a side note I have personally used pointers to interfaces for doing search tree reordering. You can really do a lot of useful pointer operations without pointer arithmetic. (A link to a quadtree implementation which uses pointers to interfaces, on line 119) https://github.com/fmstephe/location_server/blob/master/quadtree/quadtree.go https://github.com/fmstephe/location_server/blob/master/quad...
- pdw 14y agoYou don't need pointer-to-pointers to replace the entire struct, you can just do this: http://play.golang.org/p/2ZUvuyCtwr http://play.golang.org/p/2ZUvuyCtwr func main() { u := &User{Name: "Leto"} println(u.Name) Modify(u) println(u.Name) } func Modify(u *User) { *u = User{Name: "Paul"} }
- fmstephe 14y agoGood point. Thx :)
- Rygu 14y agoLooks like C pointer syntax!
- ithkuil 14y agoIndeed. They are pointers. You just cannot do pointer arithmetic on them. In declaration the '' goes on the left though. In general Go's syntax inverts the declaration w.r.t C/C++: a int vs int a b *int vs int* b type X int vs typedef int X NOTE: you can do unsafe pointer arithmetic using the "unsafe" package. You can convert any pointer to a unsafe.Pointer and then you can convert it to a uintptr. There are also library functions designed to work with that, for example atomic.AddUintptr that atomically adds an offset to a pointer. Although not intended as general use, it can be useful in low level library code. Otherwise you can do pretty much everything using slices.
- roel_v 14y ago"I understand what a pointer is," What are you trying to do, and how would you think it works in your examples? I assume you're trying to change the name of the object being pointed to, but you're just assigning a new value to a variable that is passed to a function. Therefore, when the function returns, that value is 'lost'. How could it ever change the value of a member of the object you're pointing to? I have never written a line of Go in my life, but with the knowledge that Go supports some form of pointers, it's quite easy to trace this back to how it would work in C or C++; it also wouldn't work there, either. Knowing what a pointer is is easy, it's just memorizing a definition - knowing how they work takes some experience.
- drivebyacct2 14y agoYou're displaying some basic conceptual problems with pointers. A simple Go example: func main() { u := User{Name: "Leto"} Modify(&u) } func Modify(u *User) { // u = &User{Name: "Paul"} // you could, but why? u.Name = "Paul" } I mean, if you read your code for main, you're saying "Declare u to be a pointer to a new User. Then call modify with the address of u... aka, the address of the pointer that points to the actual User object"... This is pretty much basic pointer stuff, the same as you would do in C: runnable: http://codepad.org/TeUZi1Wp http://codepad.org/TeUZi1Wp
- latch 14y agoI wanted (and miserably failed) to show that Go wasn't pass by reference (which a lot of people, including on HN, insist that it is, even though the docs and the behavior are quite clear). Of course the simplistic example doesn't make much sense, why not just reassign u.Name? My point is that you can't simply reassign u (as other have pointed out, you can by dereferencing a pointer to a pointer...which is still pass by value)
- deleted 14y ago[deleted]
- drivebyacct2 14y agoI think you're still pretty fundamentally confused. RE: "Go is pass by reference": I don't see anyone claiming that. The top comment is trying to be nice by saying that you can emulate pass by reference by passing a pointer (but you're really just passing the pointer by value). I mean, what do you think this Java code prints (objects are references, but passed by val): Runnable: http://rextester.com/JBZCLG13581 http://rextester.com/JBZCLG13581 You should also consider the good comment above displaying how you actually CAN do REAL swapping in Go: http://news.ycombinator.com/item?id=5357959 http://news.ycombinator.com/item?id=5357959 (try that in Java... heh)
- latch 14y agoIf you write that in C#, and declare the argument as "ref User u", it'll print "newName". Which is what I think pass by reference is. Java and Go (and C) are pass by value. When I started learning Go, I kept seeing people talk about pass by reference, so I assumed it really did pass by reference (despite being uncommon). I was surprised to find out that it does pass by value.
- irahul 14y ago> I understand what a pointer is, but it's entirely possible that I still don't grok Go. I don't know about you, but I understand pointers from C, and then learning assembly. Go's behavior isn't different from C here. Also, elsewhere you are discussing pass by value/pass by reference. Technically, C/Go/Java are pass by value. Passing pointers and de-referencing it is how pass-by-ref is emulated. You will notice that the top comment has qualified pass-by-reference with "passing pointers". That is colloquial terminology.
- voidlogic 14y agoGos lack of pointer arithmetic is one of the design decisions that allows go to be memory safe (http://en.wikipedia.org/wiki/Memory_safe http://en.wikipedia.org/wiki/Memory_safe) . If you need need to be naughty with pointers you can use the "unsafe" package. But some environments like GAE or Go playground do not allow this. Also some of the built-in types like channels and maps are reference types (so they are always passed by reference).
- zeeboo 14y agoEverything in Go is passed by value, even the "reference types". Those types are called reference types because they hold a reference to some value in memory, exactly like a pointer. If they were passed by reference, then we would expect this playground snip to print "false": http://play.golang.org/p/r6naknvzng http://play.golang.org/p/r6naknvzng
- voidlogic 14y agoYou are correct, I was not being clear. They are not Go reference types are not reference types in the same way that they are in other languages. When you pass a slice around are are really passing a small struct around by value (http://golang.org/pkg/reflect/#SliceHeader http://golang.org/pkg/reflect/#SliceHeader), and it is that struct that contains the pointer to the data.
- voidlogic 14y ago"Tip Or Don't Bother" This is pretty true, although I would not bother using tip if writing a small command line utility or learning Go, but for a large project this is good advice. Execution time and memory usage are greatly improved in tip, at the cost you might run into bug that has not been fixed yet. Here is the burn down to Go 1.1's release, when it hits bottom it releases. http://swtch.com/~rsc/go11.html# http://swtch.com/~rsc/go11.html# Go 1.1 RC should be out in April I believe. Also if you need to pick a Go tip build to use this is useful: http://build.golang.org/ http://build.golang.org/
- phasevar 14y agoJust how much has execution time improved? I'd love to see some benchmarks.
- voidlogic 14y agoIf you read the golang-dev google groups mailing list you will see lots of micro-benchmarks posted for specific commits. The best test is to install both stable and tip on your machine and compile your application with both. In one of my application there was a 9% improvement, in another it was 53%. When Go 1.1 is released I presume the computer benchmarks game will be updated, which might make comparison, at lease with other languages, easier.
- dewitt 14y agoThat pointer example is a little weird. A C/C++ pointer used that way wouldn't print "Leto" "Paul", either. All it would do is update the local variable to point to a new object, but the caller would still be pointing to the original. I think the poster meant to use a pointer to a pointer here (which would work as intended in both Go and C/C++).
- NateDad 14y agoThe author is obviously new to Go, and that's fine.... here's a clarification of interfaces: Interface Pointers Note that the author of a type that fulfills an interface and the consumer of a function that takes an interface both have full control over how much data is copied on a call to the function. You can control whether a type fulfills an interface, or whether a pointer to the type fulfills the interface. In Go, it is always easy to tell how much memory is being copied for any function call. type Jumper interface { Jump() } func MakeItJump(j Jumper) { // this function doesn't know what's wrapped inside the Jumper interface // and doesn't need to care j.Jump() } type Foo struct { data [10]int64 // array of 10 8 byte numbers = 80 bytes on a copy } func (f *Foo) Jump() { // we define Jump on Foo to take a copy of a pointer to a Foo. // this means that when we pass a *Foo into MakeItJump, // just a single pointer value is copied into the interface, \ // not the whole array inside Foo } type Bar uint8 func (b Bar) Jump() { // we define Jump on Bar as taking a copy of the value of Bar // since we know it only needs to copy an 8 bit integer to do so }
- matthavener 14y agoI didn't quite "get" the point of the pointer/copy option on interfaces, but this makes it crystal clear. This works around such a common problem in writing C++ templates (which is really the only equivalent polymorphism if you want to dispatch a function on a native type): template <class T> void doSomething(const T &expensiveCopy); Versus: template <class T> void doSomething(T cheapCopy); As usual, boost provides another crazy template hack to work around this issue: http://boost.sourceforge.net/libs/utility/call_traits.htm http://boost.sourceforge.net/libs/utility/call_traits.htm
- esrauch 14y agoCan you explain why this is actually a problem? Why not just always have a const T&, is there some negative in the "cheap copy" case to not copy?
- matthavener 14y ago
- pkulak 14y agoThe "interface as a pointer" thing really threw me for a loop as well. It was bothering me so much (not knowing what was actually going on), and Googling was helping so little, that I actually hopped on the Go IRC channel. The guys on there set me straight in, literally, minutes. There's a great community around Go right now. Other than that, though, everything has been pretty cut and dry. There really aren't many "gotchas" in Go.
- ISL 14y agoWhoa. Pre-coffee, I'd clicked on the link expecting to find a "List of things someone had told me about the strategy game Go". Anyone have a link to such a list? Seems like it'd be fun.
- Beldur 14y agoOne thing I learned was: Every move you play is certainly not the best. You just need to focus on making the smallest mistakes as possible.
- shurcooL 14y agoI had the opposite problem. When someone retweeted this[1], I thought it was about golang problems. [1] https://twitter.com/gogameguru/status/309695255056351232 https://twitter.com/gogameguru/status/309695255056351232
- kin3tic 14y agoWow, this displays a severe misunderstanding of how pointers work in general. It's not like the syntax for it in Go is any different, this code would look very similar in anything that has real pointers (C, for example), certainly in regards to the notation and syntax for pointers and references and such. 'I understand what a pointer is'. Questionable.
- drivebyacct2 14y agoFor reference, I posted this in a subthread above: the same example in C demonstrating using a pointer and passing it or declaring an object and passing it's address: http://codepad.org/TeUZi1Wp http://codepad.org/TeUZi1Wp
- latch 14y agoSame example in C# showing pass by reference does exist http://rextester.com/IYZE41714 http://rextester.com/IYZE41714
- deleted 14y ago[deleted]
- toddh 14y ago>func ServeHTTP(res http.ResponseWriter, req *http.Request) I'd always wondered about that too. Thanks for one less mystery in the world.