Go's method receiver: Pointer vs Value
Tags: go, code, programming
Published: 2019-03-02 10:53:37

---
title: "Go's method receiver: Pointer vs Value"
cover_image: https://thepracticaldev.s3.amazonaws.com/i/cjxnuoddwat3zydardav.png
canonical_url: https://devopsian.net/posts/go-ptr-vs-value/
published: true
description: Go pointer vs value receiver
tags: ["go", "code", "programming"]
---


# Introduction

*This topic is huge, and there is plenty of information online. This blog tries to keep it short, and useful for experienced programmers that are new to Go.*

Coming to Go from Python introduced me to a new concept I didn't had to put thought into.
Python is a pass-by-object-reference language. You have no direct control over that.
What this means is, when you pass an object (*everything in Python is an object*) to a function,
you pass a *reference* to the object itself. 

We can see it using the `id()` function, which *returns the* ***identity*** *of an object.* This identity has to be **unique** and **constant** for this object during its lifetime.

```python
>>> def action_with_string(s):
...     print(id(s))
...
>>> v = "sample string"
>>> id(v)
4360321520
>>> action_with_string(v)
4360321520
>>>

# A list example

>>> ls = list()
>>> def append_list(l):
...     l.append(1)
...
>>> append_list(ls)
>>> ls
[1]
>>> append_list(ls)
>>> ls
[1, 1]
```

The object inside a function is the same as the caller object. 
Whatever you pass, can be mutated (as long as it is mutuable). It is discussed on [StackOverflow: Python functions call by reference](https://stackoverflow.com/questions/13299427/python-functions-call-by-reference), if you are interested reading further.

With Go, when you define a method on a struct, you choose if the receiver (*the object which the method is executed on, kind of self in Python*) is of type Value or a Pointer.

**What does this means, anyway?**

In simple terms, ***value receiver*** makes a copy of the type and pass it to the function. The function stack now *holds an equal object* but at a different location on memory.

***Pointer receiver*** passes the *address of a type* to the function. The function stack has a *reference* to the original object.

A simple example shows the difference.

```go
package main

import (
	"fmt"
)

type Bike struct {
	Model string
	Size int
}

func ValueReceiver(b Bike) {
	fmt.Printf("VALUE :: The address of the received bike is: %p\n", &b)
	// Address of the object is different than the ones in main
	// Changing the object inside the scope here won't reflect to the caller
	b.Model = "BMW"
	fmt.Println("Inside ValueReceiver model: ", b.Model)
}

func PointerReceiver(b *Bike) {
	fmt.Printf("POINTER :: The address of the received bike is: %p\n", b)
	// Address of the object is the same as the ones in main
	b.Model = "BMW"
	fmt.Println("Inside PointerReceiver model: ", b.Model)
}

func main() {
	v := Bike{"Honda CBR", 650}
	p := &Bike{"Suzuki V-Storm", 650}
	
	fmt.Printf("Value object address in main: %p\nPointer object address in main: %p\n\n", &v, p)
	ValueReceiver(v)
	fmt.Println("Value model outside the function: ", v.Model)
	
	fmt.Println("")
	PointerReceiver(p)
	fmt.Println("Pointer model outside the function: ", p.Model)
}


// OUTPUT
Value object address in main: 0x40a0e0
Pointer object address in main: 0x40a0f0

VALUE :: The address of the received bike is: 0x40a100
Inside ValueReceiver model:  BMW
Value model outside the function:  Honda CBR

POINTER :: The address of the received bike is: 0x40a0f0
Inside PointerReceiver model:  BMW
Pointer model outside the function:  BMW
```

## So when should you use what?

Regardless of what you choose, it is best practice to keep uniformity of the struct methods. If the struct uses both types, it is hard to track which methods uses which types, especially if you weren't the one who wrote the code.
So try your best they all use the same receiver for **consistency**.

### Pointers

* If you want to share a value with it's methods

If the method *mutates the state* of the type, you must use a pointer or it won't work as expected. Value receiver changes are local to the copied object and lives only inside the function scope .

* If the struct is very large (optimization)

Large structs with multiple fields may be costy to copy everytime they need to be passed around.
If you are in such case, I think you should consider breaking it down to smaller pieces. If that's not possible, use pointer.
Optimization *usaully* adds **complexity**. Always think twice before you use it.

Note that *pointers* are not safe for concurrency; hence you need to handle it yourself using synchronous mechanism such as *channels, or the use of atomic or sync builtin packages*.

### Values

* If you don't want to share a value, use value receiver.

Value receivers are **safe for concurrent access**. One of the biggest Go advantages is *concurrency*, so this is huge plus.
You never can know when you would need it, and if you write library code you can be sure someone at some point will use it concurrently.

# Summary

This was an interesting subject for new comers like me. It is a new concept I didn't deal with prior to developing in Go.
After researching the subject thru blogs, documentation, videos and almighty Stackoverflow I have came up with a small set of "rule of thumbs" to remember:

1. Use the same receiver type for all your methods. This isn't always feasible, but try to.
2. Methods defines a *behavior* of a type; if the method uses a *state* (*updates / mutates*) use **pointer** receiver.
3. If a method don't mutate *state*, use **value** receiver.
4. Functions operates on *values*; functions **should not** depend on the state of a type.

Here's a list of great resources if you want to explore deeper:

* [Steve Francia "7 common mistakes in Go" talk on YouTube](https://www.youtube.com/watch?v=29LLRKIL_TI)
* [Comments from Go Code Review team](https://github.com/golang/go/wiki/CodeReviewComments#receiver-type)
* [Gopher vs Object Oriented](https://medium.com/gophersland/gopher-vs-object-oriented-golang-4fa62b88c701)
* [T and T* have different method sets](https://golang.org/doc/faq#different_method_sets)