Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What's the point of having pointers in Go?

Tags:

pointers

go

I know that pointers in Go allow mutation of a function's arguments, but wouldn't it have been simpler if they adopted just references (with appropriate const or mutable qualifiers). Now we have pointers and for some built-in types like maps and channels implicit pass by reference.

Am I missing something or are pointers in Go just an unnecessary complication?

like image 403
anon Avatar asked Dec 07 '09 22:12

anon


People also ask

Why do we need pointers in Go?

Go has pointers. A pointer holds the memory address of a value. The data is stored in the memory when the program runs and each has a number- the memory address, which can be assigned to a pointer, and through which we can find the data stored in memory.

Why You Should Avoid pointers in Go?

Accidental Mutation When you pass a pointer to a function, you don't know if it gets edited or not. This adds complexity to your codebase and as the code grows, it becomes really easy for an error to slip in because somewhere deep in the call stack, the pointer struct is changed.

How do pointers work in Go?

In Go a pointer is represented using the * (asterisk) character followed by the type of the stored value. In the zero function xPtr is a pointer to an int . * is also used to “dereference” pointer variables. Dereferencing a pointer gives us access to the value the pointer points to.

Are pointers faster Golang?

But passing pointers in Go is often slower than passing copied values. This is because when pointers are passed into functions, Go needs to perform an escape analysis to work out whether the value needs to be stored on the stack or in the heap.


2 Answers

Pointers are usefull for several reasons. Pointers allow control over memory layout (affects efficiency of CPU cache). In Go we can define a structure where all the members are in contiguous memory:

type Point struct {   x, y int }  type LineSegment struct {   source, destination Point } 

In this case the Point structures are embedded within the LineSegment struct. But you can't always embed data directly. If you want to support structures such as binary trees or linked list, then you need to support some kind of pointer.

type TreeNode {   value int   left  *TreeNode   right *TreeNode } 

Java, Python etc doesn't have this problem because it does not allow you to embed composite types, so there is no need to syntactically differentiate between embedding and pointing.

Issues with Swift/C# structs solved with Go pointers

A possible alternative to accomplish the same is to differentiate between struct and class as C# and Swift does. But this does have limitations. While you can usually specify that a function takes a struct as an inout parameter to avoid copying the struct, it doesn't allow you to store references (pointers) to structs. This means you can never treat a struct as a reference type when you find that useful e.g. to create a pool allocator (see below).

Custom Memory Allocator

Using pointers you can also create your own pool allocator (this is very simplified with lots of checks removed to just show the principle):

type TreeNode {   value int   left  *TreeNode   right *TreeNode    nextFreeNode *TreeNode; // For memory allocation }  var pool [1024]TreeNode var firstFreeNode *TreeNode = &pool[0]   func poolAlloc() *TreeNode {     node := firstFreeNode     firstFreeNode  = firstFreeNode.nextFreeNode     return node }  func freeNode(node *TreeNode) {     node.nextFreeNode = firstFreeNode     firstFreeNode = node } 

Swap two values

Pointers also allows you to implement swap. That is swapping the values of two variables:

func swap(a *int, b *int) {    temp := *a    *a = *b    *b = temp } 

Conclusion

Java has never been able to fully replace C++ for systems programming at places such as Google, in part because performance can not be tuned to the same extend due to the lack of ability to control memory layout and usage (cache misses affect performance significantly). Go has aimed to replace C++ in many areas and thus needs to support pointers.

like image 154
Erik Engheim Avatar answered Oct 18 '22 11:10

Erik Engheim


I really like example taken from http://www.golang-book.com/8

func zero(x int) {     x = 0 } func main() {     x := 5     zero(x)     fmt.Println(x) // x is still 5 } 

as contrasted with

func zero(xPtr *int) {     *xPtr = 0 } func main() {     x := 5     zero(&x)     fmt.Println(x) // x is 0 } 
like image 34
Piotr Kochański Avatar answered Oct 18 '22 10:10

Piotr Kochański