Sunday, August 30, 2015

Pass by Value vs. Pointers

When you call a function with parameters and pass an argument to it, Go by default pass the argument by copying it (i.e. pass by value). If you want to pass by reference use pointers. 

What does this mean?

For an Introduction to Pointers read Go Pointers

When an argument is passed by value, a function receiving a value will receive a copy of the original value and when you mutate (change) this value it will mutate the copy and not the original value. Let us see the following example:

Example RefCode# 1: Pass by Value

package main

import "fmt"

type Player struct {
 Name  string
 Score int
}

func currentScore(p Player) int {
 p.Score++
 return p.Score
}
func main() {
 arg := Player{Name: "Messi", Score: 101}
 fmt.Printf("%s just scored his %dth goal.\n", arg.Name, currentScore(arg))
 fmt.Printf("Now "+"%s has a total of %d goals.", arg.Name, arg.Score)
}

Output


Messi just scored his 102th goal.
Now Messi has a total of 101 goals.


Play with the above code

The intention of the above code is to show that Messi has just scored one more goal so total number of goals scored by him should become 101+1 i.e. 102. The second statement of the above code is wrong as it is still showing the old value (i.e. 101) in case of total number of goals scored! This has happened because we've changed the copy and not the original value!

See how the output differs when we pass the value by pointer instead of value. The following code shows the desired result:

Example RefCode# 2Pass by Pointer


package main

import "fmt"

type Player struct {
 Name  string
 Score int
}

func currentScore(p *Player) int {
 p.Score++
 return p.Score
}

func main() {
 arg := &Player{Name: "Messi", Score: 101}
 fmt.Printf("%s just scored his %dth goal.\n", arg.Name, currentScore(arg))
 fmt.Printf("Now "+"%s has a total of %d goals.", arg.Name, arg.Score)
}

Output
Messi just scored his 102th goal.
Now Messi has a total of 102 goals.

Play with the above code




What's the Difference Between RefCode# 1 & RefCode# 2?
The two code samples are same except the following 2 lines. Have a look and try to assimilate how pointer is used.

func currentScore(p Player) int {
vs.
func currentScore(p *Player) int {
----------------------------------------
arg := Player{Name: "Messi", Score: 101}
vs.
arg := &Player{Name: "Messi", Score: 101}
What are the Benefits of Pointers?

1. In contrast to the value type receiver, a pointer receiver is extremely lightweight (4 or 8 bytes) as only the pointer (a reference i.e. an address and not the actual value) is copied and not the entire value. 
2. you must use a pointer in cases where the argument value needs to be modified (like in the above example).
Official version from Go FAQs
I've copied and pasted it here for your reference [source]:
As in all languages in the C family, everything in Go is passed by value. That is, a function always gets a copy of the thing being passed, as if there were an assignment statement assigning the value to the parameter. For instance, passing an int value to a function makes a copy of the int, and passing a pointer value makes a copy of the pointer, but not the data it points to. Please share if you liked it.

No comments:

Post a Comment