website logo

Last Updated:

What is Method and Pointer Indirection in Golang

feature.webp

Golang is not an object-oriented programming language. But you can define methods on types using receiver functions. Now the question that comes to your mind is, what is a receiver function? is it different from normal function?

In this blog, you will learn how methods are defined in Golang using receiver functions, and if they are pure functions as they claim to be.

How Methods are defined in Golang

Before discussing what methods look like in Golang, first define a struct named Person. As we know, every person at least has a name and age. We define the name and age fields in the Person struct in Golang.

type Person struct{
    name string
    age int
}

Now, let’s define a method birthYear() on the Person struct to calculate the birth year of that person.

func (p Person) birthYear() int {
    year, _, _ := time.Now().Date()
    return year - p.age
}

Here you can see that birthYear is a regular function with a receiver p of type Person. The receiver is defined between the func keyword and the function name itself. Due to this receiver, now birthYear function acts as a method of the Person type.

func main() {
    p := Person{"hrishikesh", 24}
    fmt.Println(p.birthYear())
}

You can now use the birthYear() method on the Person type to calculate the birth year of that person.

Is methods are functions in Golang

As you can see methods are nothing but functions with a receiver. You can also rewrite the above birthYear method as a function. Let’s see how it turns out.

func birthYearFunc(p Person) int{
    year, _, _ := time.Now().Date()
    return year - p.age
}


func main() {
    p := Person{"hrishi", 24}
    fmt.Println(birthYearFunc(p))
}

One very important thing I want to point out is that you can define methods on types that are defined inside the same package. You can’t define methods on types from other packages. For example, you can define methods on the Person type, as it is defined on the main package. But you can’t define any method on string or int types which is defined in other packages.

Understand Method and pointer indirection in Golang

First, let’s make a changeName method to change the name of a Person.

func (p *Person) changeName(newName string) {
    p.name = newName
}

func main() {
    p := Person{"hrishi", 24}
    p.changeName("John")
    fmt.Println(p)
}

// Output
{John 24}

Usually, when you pass an argument to a function(or methods), a copy of that value is received by the function. When the function modifies the value, the original value doesn’t change.

on the contrary, if you pass a pointer to the function argument, the actual value is changed.

Here I pass the pointer of the *Person type as a receiver to the changeName method. When the changeName method modifies p, the actual value of p got changed. This is because p is not a copy but a pointer reference(i.e. *Person) to the Person type. That’s why, you can see the name is changed at the output.

Pointer methods are useful when you want to modify something and hence, they are most common in the Golang world. Let’s convert the changeName method into a function.

func changeNameFunc(p *Person, newName string) {
    p.name = newName
}

func main() {
    p := Person{"hrishi", 24}
    changeNameFunc(&p, "John")
    fmt.Println(p)
}

// Output
{John 24}

Can you spot a difference in the code examples? In the previous example, although we define the changeName method on a pointer receiver, you can use it with the value p without explicitly converting it to a pointer first. In this case, the Golang compiler automatically converts the value p into its pointer &p.

p.changeName("John")

// What Go does internally
(&p).changeName("John")

But in the case of chnageNameFunc function, as the argument needs a pointer of type *Person, we have to explicitly convert p into &p pointer and then pass the argument to run the code.

Remember, If a function takes a pointer as an argument, you have to pass a pointer. But methods can use both. This difference in method and function is called Methods and Pointer indirection in Golang.

Similarly, if a function takes a value argument, you have to pass a value. But methods can accept both value and pointer and convert into both when necessary. Let’s modify the birthYear method and try to invoke it with a pointer.

func main() {
    p := Person{"hrishi", 24}
    pp := &p
    fmt.Println(pp.birthYear())
}

Here pp is a pointer to the p value. When we call pp.birthYear() method, the Golang compiler converts the pointer into a value and calls the method as (*pp).birthYear().

But if you try to pass the pp pointer to the birthYearFunc function, it gives you an error. BirthYearFunc() only accepts a value as its argument.

func main() {
    p := Person{"hrishi", 24}
    pp := &p
    fmt.Println(birthYearfunc(*pp))
}

Conclusion

If you understand method and pointer indirection in Golang using this blog, please consider sharing with your peers. Subscribe to the newsletter to get a weekly newsletter with this type of programming content delivered to your inbox.

See Also