Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Passing pointers vs. value in Go

Tags:

pointers

go

I've read this interesting blog post that is totally unrelated to Go and one thing the author said caught my attention, this following quote:

... For example, it is efficient to pass a channel as the parameter of a function all, because a channel in Go is as simple as a pointer to the channel data structure implemented in C. It is the same for map and some other types. But it is inefficient to pass an array or struct; instead, we should pass pointers to these types.

Why is it inefficient to pass pointers when using some of Go internal types or structs?

like image 396
ymg Avatar asked Nov 04 '13 03:11

ymg


2 Answers

The context is relevant here:

However, the type system of Go is so complex; programmers need to know all the details about the implementation of standard types, before they can use them correctly. For example, it is efficient ...

The author is saying that maps and channels look like values but act like pointers when they are copied.

For other datatypes, the parameter has a * in it, which is a clear signal it could be modified in place. Often the argument has a & in front as well, which is another signal that the argument is being modified.

When passing maps and channels, those syntactic signals are not there. That leads to unexpected results like this one:

http://play.golang.org/p/lS1FXZnxb8

A similar criticism could be applied to the big difference between arrays like [256]byte and slices like []byte, where the absence of a size is the only signal of different copying behavior.

All of this being aside, the author incorrectly equates copying and inefficiency. It is true that copying sometimes requires more CPU cycles or memory accesses than passing a pointer. However, that is not always the case. It depends on the size of the structure and optimizations performed by the compiler.

The decision to copy, i.e. pass a value, vs. pass a pointer is also about whether the argument might be modified by the function.

For small structures and arrays which are not intended to be modified by the function, pass them by value. This eliminates an entire class of bugs caused by accidental modifications in place, and is even better than const as used in other languages, because there is no way to cheat and get around it. Of course, always be careful with embedded pointers, including maps and slices, because those may still be modified inside the function.

like image 160
Sean Avatar answered Oct 06 '22 09:10

Sean


It's not inefficient to pass pointers. But the author is correct: because arrays and structs are passed by value by default, their contents are copied to each new function call. This can be inefficient.

According to Go slices: usage and internals, arrays are passed by value. (Slices use a pointer to the array under the hood, so they're more efficient to pass.)

Like slices, channels are allocated by make (at least implicitly) and so channels act as a reference to the actual data structure.

So when you're working with structs and actual arrays, typically you'll pass their reference instead. (See Sean's answer for more detail about this. He makes a good point that copying isn't always inefficient. Sometimes it is desirable.)

like image 31
Matt Avatar answered Oct 06 '22 07:10

Matt