18

On the closest thing Golang has to a style guide found here, under Receiver Names this is written:

The name of a method's receiver should be a reflection of its identity; often a one or two letter abbreviation of its type suffices (such as "c" or "cl" for "Client"). Don't use generic names such as "me", "this" or "self", identifiers typical of object-oriented languages that place more emphasis on methods as opposed to functions. The name need not be as descriptive as a that of a method argument, as its role is obvious and serves no documentary purpose.

I personally have always just used "this" as the identifier because "this" is the focus of what I am working on when I write and edit the function. It sounds right, and (to me at least) it makes sense.

If the name need not be descriptive, it's role is obvious, and it serves no documentary purpose, why would the use of "this" be frowned upon?

Alexander
  • 5,185
Adam
  • 1,397

5 Answers5

14

I am not convinced by this style guide and I don't think anything is better than this, me or self. Because this, me or self makes it super clear that the variable is an instance of the context struct. I'm not saying a lower cased struct name variable is a bad idea, I just like the way that this makes it super clear.

Qian Chen
  • 256
12

We'd have to ask the author of that style guide to know for sure, but I think the main reason I kind of agree with him is that the connection between struct and method is much looser in Go than other languages.

In essence, when you write a method like this:

func (m *MultiShape) area() float64 {
  ...
}

That's almost exactly the same thing as writing a function like this:

func area(m *MultiShape) float64 {
  ...
}

The only difference is a slight syntax change in how we call the function/method.

In other languages the this/self/whatever variable typically has some special properties such as being magically provided by the language, or having special access to private methods (remember Go doesn't have private fields/methods). Though the "receiver" is still being "magically provided" to some extent, it's so similar to a regular function argument it arguably doesn't count.

Plus, in "traditional" OOP languages a struct/class' methods all come with the struct/class definition, such that no more can be added from outside. In Go, as far as I know anyone can add more methods to anything (within the scope of their own code, of course).

I haven't written enough Go to make my own style guide, but personally I'd probably use this in methods defined in the same file as the struct they receive, and some more descriptive receiver name on methods that I attach to structs from other files.

Ixrec
  • 27,711
4

I have realized this only while reading the answers here:

There is a real and significant difference between receiver in Go and this/self in most (all?) OOP languages: receiver is never polymorphic.

When you have a method in C++ or Java and call this.someMethod(foo) then at this call site, without looking up the signature, you can't tell whether this method may be overriden or not. In Go, you know it isn't - you don't even have a real inheritance in Go, so there are no overrides. This can be both useful and limiting. On one hand, it prevents some unlucky overrides from breaking the logic for the base class, which may happen with virtual inheritance. On the other hand, it prevents doing things traditional, OOP way.

I actually wrote a simple test to make sure I didn't imagine something (it's quite late and I'm not feeling sharpest right now :P):

package main

import "fmt"

type BaseStruct struct { baseVal int }

func (t BaseStruct) callNotPolymorphicOnSelf() string { // Always calls notPolymorphic defined for BaseStruct, no matter what this struct is composited into. return t.notPolymorphic() } func (t BaseStruct) notPolymorphic() string { return "<executing (BaseStruct) function>" }

type ComposedStruct struct { BaseStruct addedVal int }

func (t ComposedStruct) notPolymorphic() string { return "<executing (ComposedStruct) function>" }

type interfaceThatChangesNothing interface { callNotPolymorphicOnSelf() string }

func fromIface(it interfaceThatChangesNothing) string { return it.callNotPolymorphicOnSelf() }

func main() { var composedStruct ComposedStruct fmt.Printf("Calling composedStruct.callNotPolymorphicOnSelf(): %v\n", composedStruct.callNotPolymorphicOnSelf()) fmt.Printf("Calling callNotPolymorphicOnSelf() through interface: %v\n", fromIface(&composedStruct)) fmt.Printf("Calling notPolymorphic directly on composedStruct: %v\n", composedStruct.notPolymorphic()) }

Result:

Calling composedStruct.callNotPolymorphicOnSelf(): <executing (*BaseStruct) function>
Calling callNotPolymorphicOnSelf() through interface: <executing (*BaseStruct) function>
Calling notPolymorphic directly on composedStruct: <executing (*ComposedStruct) function>

See live in Go Playground

Frax
  • 1,874
0

This is from a perspective of JavaScript where this has actual keyword meaning to the compiler, but from my understanding, if they're okay with two-letter abbreviations for the object type, it should be easy enough to use that instead. The reason for the difference is that in a decently-large block of progressively deeper asynchronous code, it could be very easy to misinterpret what "this", or the receiver, is in a deeper context; and it's possible it won't be the same object.

In JavaScript for instance, a control module might start up a dialog and declare an onLoad function inline for it. But at that point, it could be very easy for another coder to misinterpret this inside onLoad to refer to the control module, not the dialog; or vice versa. This could be avoided if the control were referred to as ctrl and the dialog as dg.

Katana314
  • 882
0

I'm firmly in the camp that this of self should not be used in Golang. It confuses other engineers on the behavior of the language if they are coming from something like PHP, Java, Python or JS. Here are some pretty good examples of why it could and probably will cause confusion: https://blog.heroku.com/neither-self-nor-this-receivers-in-go

There are no classes in Golang and it's not an OOP language so I personally would avoid it.

Shoe
  • 1