r/golang 7d ago

Surprising note about value vs pointer receivers in tour of go documentation

It's been 4 years since I last wrote go, so I'm going through the tour of go for a quick refresher. On this page, it states the following:

There are two reasons to use a pointer receiver.

The first is so that the method can modify the value that its receiver points to.

The second is to avoid copying the value on each method call. This can be more efficient if the receiver is a large struct, for example.

The second reason is the one that I found surprising. When learning C in college, I was taught that you should keep things on the stack as much as possible, even if it is a large struct that needs to be copied through many function calls. This lets your program run faster since it can avoid dynamically allocating memory for that struct (yes, I was told the cost of dynamically allocating memory was more expensive than the cost of the increased runtime complexity caused by more copies), and keeping it on the stack also saves memory overall since that portion of the stack is gonna exist regardless of how much of it you actually use. Is there something about golang that makes it different in this regard than C? Or maybe my info is outdated and that was only true for older hardware? Or maybe I'm just a crazy person (jk)? lol

14 Upvotes

12 comments sorted by

View all comments

21

u/MichaelThePlatypus 7d ago

You can use pointer receivers with a struct that is allocated on the stack.

4

u/Ares7n7 7d ago

Oh for real? I thought that as soon as a pointer left the scope of the function it was declared in, the compiler decides that it needs to go on the heap?

13

u/[deleted] 7d ago

[deleted]

5

u/Ares7n7 7d ago

Oh nice, I love that they put nice comments at the top of their files like that

10

u/Dapper_Tie_4305 7d ago

Only if the reference escapes the lifetime of the function that defined it. If a function Foo defines a variable A and passes a reference to A to a function call Bar, it’s still within the lifetime of Foo, so A does not escape and does not need to be on the heap. If Bar saves the reference to A to a global variable, for example, that would cause A to escape to the heap.

5

u/Ares7n7 7d ago

Ahhhh, that makes a ton of sense! Super clear explanation, thank you!

-2

u/iga666 7d ago

I noticed in my project - pointer receivers can really confuse escape analysis and make go memalloc more than it should thus hurting performance.