In Go is naming the receiver variable ‘self’ misleading or good practice?

In addition to what others said (especially PeterSO and dskinner—in his comment to the Peter’s answer), note several important things:

You can call a method like a simple function

In Go, you can call any method function not as a method on a receiver but rather as a regular function—simply by qualifying its name with the name of the type it’s defined to be a method on and explicitly passing it a receiver argument (obtaining a simple function from a method is called
using a method expression).

To demonstrate:

package main

import "fmt"

type Foo int

func (f Foo) Bar() {
    fmt.Printf("My receiver is %v\n", f)
}

func main() {
    a := Foo(46)
    a.Bar()
    b := Foo(51)
    Foo.Bar(b)
}

(Playground link.)

When run, this program prints:

My receiver is 46
My receiver is 51

As you can see, self loses its sacred meaning here because you’ve just called a method artificially constructing the context for it which has nothing to do with the much cited “calling an object’s method is passing a message to that object” concept.

To recap, in Go, a method is just a function semantically bound to a particular type which receives a single extra argument—its receiver—no matter how it’s called. Contrary to many other mainstream languages, Go does not hide this fact under the carpet.

A receiver is not necessarily mutable inside a method defined on its type

As demonstrated in my example, I’ve defined a method, Bar(), on a non-pointer receiver, and if you’ll try to assign a value to the receiver that will succeed but won’t affect the caller because the receiver—as everything in Go—has been passed by value (so that integer has just been copied).

To be able to mutate the receiver’s value in the method, you’d have to define it on an appropriately-typed pointer, like

func (f *Foo) Bar() {
    // here you can mutate the value via *f, like
    *f = 73
}

Again, you can see that using self meaning “me”, “my internals” becomes moot here: in my example the method merely received a value which type it knows. You can see this is in contrast with many OO-languages in which an object is a black box usually passed around by reference. In Go, you can define a method on virtually anything (including other methods, which is used by the net/http standard package, by the way) which erodes that “methods are for objects” concept.

Different sets of methods might be applicable to the same value at different times

In Go, methods are a convenient way to group functionality around particular types, and different sets of methods might be applicable to the same value in different points of the program flow. Combined with interfaces and duck-typing they provide, this concept really flourishes. The idea is that in Go, there’s an idiom of defining “support” types which perform certain operation on values of some other type.

A good example of this is the standard package sort: for instance, it provides the type IntSlice which allows you to sort a slice of integers—a value of type []int. To do that you type-convert your slice to sort.IntSlice and the value you get as a result has a whole set of methods for sorting your slice while the internal representation of your value has not changed— because sort.IntSlice is defined as type IntSlice []int. In each method of that IntSlice type, it’s hard to reconcile the meaning of their receiver value with self—simply because the type solely exists to provide a set of methods for another type; in a philosophical sense, such utility types have no concept of “self” 😉

Conclusion

So I’d say, keep things simple in your head and do not try to “overload” the clear and simple approach taken by Go with semantics it does not explicitly state it provides.

One more note. My personal perception of Go’s idioms as I learned them is that the paramount property of Go is its practicality (as opposed to idealism etc) so if you see some concept which “feels” unnatural try to work out why it’s designed that way, and most often you’ll discover why so the concept “clicks” in your brain and gets natural. (I must admit that to grok this particular problem with understanding methods in Go, a good working familiarity with C would be of much help.)

Leave a Comment