16

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?

1

5 Answers 5

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.

6
  • That's a good explanation, I suppose I'm used to C# and other OOP languages so I'm reverting to conventions I know.
    – Adam
    Jun 11, 2015 at 8:23
  • 1
    @Adam I would avoid this if for no other reason than to remind myself that I'm not in a traditional OOP language. Jul 9, 2016 at 0:03
  • 8
    There is no real difference between "this" and "receiver" (and please stop abusing word "magic" - every feature of a high level programming language can be called "magic", this doesn't make it anything negative, your attempt to pick on "this" for being "magic" makes no sense).
    – mvmn
    Jul 5, 2017 at 14:04
  • @mvmm Extreme care and diligence needs to be taken though in explaining magic to someone who is not familiar with it. It is not by chance witches used to be burned by the stake.
    – Zyl
    Feb 19, 2021 at 13:23
  • I guess the only "magic" that really can make a difference is that this in garden-variety OOP languages can be polymorphic, while in Go it never is? Personally, I never understood the big deal people make about method/function distinction. Perhaps this is because of my C++ background, which means that for me every method is just a function, except when virtual - than it's still just a function, but with funny call semantics. Though it's true that this is polymorphic in C++ too, also in non-virtual methods - so maybe I just wasn't appreciating the difference enough?
    – Frax
    Jan 28, 2022 at 1:12
12

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.

3
  • without an explanation, this answer may become useless in case if someone else posts an opposite opinion. For example, if someone posts a claim like "I am convinced by this style guide and I think it is better than this, me or self", how would this answer help reader to pick of two opposing opinions? Consider editing it into a better shape, to meet How to Answer guidelines
    – gnat
    Dec 26, 2016 at 5:05
  • I think I have clearly explained what I wanted to say.
    – Qian Chen
    Jan 10, 2018 at 7:55
  • 1
    I agree. I think there are too many brains poisoned by the javascript context. If you put that aside. That this refers to the current context is much simpler. And easier if you rename structs later on, or copy paste part of an implementation. Gong for short cryptic names line h. l. etc does not make it any easier than this.
    – Sentient
    Jun 8, 2018 at 15:37
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

3
  • 1
    This is a good answer, as it highlights the advantage of using Go's conventions. this and self have meaning other than Go's definition of "receiver", and what it can and can't do. So changing the convention has the potential to push you to think :)
    – dror
    Apr 15, 2022 at 22:45
  • I'm a very seasoned OOP developer and somewhat new to Go, so maybe I'm missing something, but here's a hot take: the fact that Go doesn't have inheritance (let alone classes) means that the confusion about polymorphic subtleties with respect to "this" will simply never arise. That being the case, why worry about it?
    – JakeRobb
    Oct 26, 2023 at 21:02
  • I'd say it is not that obvious. The polymorphism is still present in the interfaces, and while there is no proper inheritance, there is still the composition (which is, BTW, almost identical to basic (non-virtual) inheritance in C++). There is actually a lot of space for confusion, so making the receiver different from this or self is just as much help to underline the difference with OOP methods as can go into the syntax, I think.
    – Frax
    Feb 1 at 1:34
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.

3
  • 4
    I'm not the downvoter, but most of the confusing behaviors of this in Javascript simply do not apply to Go, so I'm guessing that's why.
    – Ixrec
    Jun 10, 2015 at 16:21
  • @Ixrec Hm...okay. I was kind of trying to extend it to situations where you could choose this's name; for instance, often JS coders will write var self = this to keep the same reference around; but according to Go's design guide, that could then have the same confusion issues, and theoretically should use a more descriptive reference.
    – Katana314
    Jun 10, 2015 at 17:12
  • With arrow functions this issue is fortunately mostly extinct in JS too, though you still can do any weird nesting, nested classes with methods with nested classes and so on. However, in Go you don't have these all weird kinds of nesting, so shadowing issues don't apply to this.
    – Frax
    Jan 28, 2022 at 1:13
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.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.