DEV Community

Cody Potter
Cody Potter

Posted on

The case for `self` receivers in Go

Ok ok, hear me out. I know you're already lighting torches and sharpening your pitchforks (Side note: Can you sharpen a pitchfork?). I know I'm probably in the minority here, so please allow the little-guy to make a small case for the use of self as a receiver name.

Counterarguments

In an attempt to not straw-man, I want to present as strong of a counterargument I've come across, Refactors. If you use the keyword self for all of your receivers, but you need to move a method from one type to another, suddenly, you are forced to rewrite the context of the method. This specifically becomes a problem when you're moving code between levels of abstraction.

I would however argue that moving logic between levels of abstraction should require you to rethink and restructure your code anyway. No one should expect copying and pasting code from one layer to another should "just work".

The current meta

Go has an official stance on the naming of method receivers.

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 gives the method a special meaning. In Go, the receiver of a method is just another parameter and therefore, should be named accordingly. The name need not be as descriptive as that of a method argument, as its role is obvious and serves no documentary purpose. It can be very short as it will appear on almost every line of every method of the type; familiarity admits brevity. Be consistent, too: if you call the receiver "c" in one method, don't call it "cl" in another.

I'd like to argue that the very last sentence there completely contradicts all of the previous statements, "Be consistent". Idiomatic go code aims to be clear above all else. Having no reserved keyword to use as the name for the method's owner leaves an opportunity for a lack of clarity. Extremely short variable names have a tendency to collide with other names and have the same result.

There is no mechanism enforcing consistency here. There's nothing stopping the programmer from giving every method a different receiver name for the same type. For example, a type Server could have any of the receiver names s, srv, server, or sv. You might be able to make a case for this if you had been using s for all your previous methods, but then you have to add a new function signature like:

func (server Server) CashOut (s Service)
Enter fullscreen mode Exit fullscreen mode

From inside the function, the short variable naming begins to work against you. Does s represent the Server or the Service? You'd have to either:
A. Break your previous pattern of using s as the receiver.
B. Break the pattern of short variable naming and name use a name like service for the Service.
Either way, this is unclear, and you're forced to break a rule.

Certainly not OOP

Go insists strongly that it does not have classes. However, you can define methods on types. Sure, Object-Oriented-Programming and classes come with a lot of baggage. However, I'd argue that simply referring to these functions as methods lets the cat out of the bag. We're attaching a function to an obje --cough cough, excuse me, type. We're defining a method on a type. Go treats the receiver as if its an additional argument to the function.

Go insists that a receiver is just syntactic sugar for an additional parameter. But don't get it twisted! A type can only satisfy an interface if all the methods are defined on the type 😉.

It's beginning to sound like we're having our cake and eating it too! I'm a little confused why the designers of Go are so staunchly opposed to reserving a keyword for the receiver but then rely so heavily on the concept of methods which originates from object oriented programming.

The language has basically cracked a window for code smells to leak into. The proverbial window is programmer-defined keywords and the smell is bad variable naming.

To swap metaphors for a second, gifting the programmer with the ability to name the method receiver is a cafe door that swings both ways. Sure you have the ability to customize your receiver name to something that reads very nicely, but that cafe door can come swing back and smack you in the face when you rework your type and now the name no longer reads nicely. Or you just flat out picked a bad name that isn't working in your favor any longer.

In short, TLDR

If we really care so much about consistency, reserve a keyword for method receiver and be consistent about it. Pick a word and stick with it. I'll be using self.

I'd love to hear strong counterarguments and be proven wrong. I love this language and I'd love to be on board with the design, but I have yet to hear a good argument for single-letter names for variables or receivers.

Top comments (7)

Collapse
 
chadcatlett profile image
Chad Catlett

Growing up we used a fairly corse stone wheel that was easily 100+ years old for sharpening our elderly neighbor's tined tools like pitch forks. It was mounted on a basic axel with a pretty awful bearing and had a water hose attachment that we never hooked up.

So yes you can and do for optimal performance. =)

Collapse
 
ccoveille profile image
Christophe Colombier

Honestly, I would say: do as you want.

One simple thing, for me consistency doesn't mean uniqueness. The way, I understand is the fact:

  • you should use the same variable name across all methods that use the same receiver, most linters enforce such usage.
  • if you used something short for one type/struct, do not use an extremely long variable name on the next type/struct.

I disagree and dislike the way you do it, so I drop a comment but I won't fight to convince you that you are doing awkward to me.

I would tend to apply the recommendation you quoted in your post.

If you find it more convenient to do it that way, then do it.
I'm unsure you will find people using the same convention as you in golang community.

Especially when documentation says not do it.

But that said, there is no problem to disagree on something.

I know it's not the explanation you were looking for. But I wanted to drop a message.

Collapse
 
ccoveille profile image
Christophe Colombier

You might find some interesting contents here.

I have seen a fair amount of blogs & videos on Go and as far as I recall, none of the authors use 'self' or 'this' for the receiver variable when writing methods. However there seems to be a number of questions on stack overflow that do this, and it…

Neither self nor this: Receivers in Go | Heroku

Andrey Petrov is the author of urllib3, the creator of Briefmetrics and ssh-chat, and a former Googler and Y Combinator alum. He’s back again to free us of

favicon blog.heroku.com

Also some linters report what uou use as errors

Checks | Staticcheck

Explanations for all checks in Staticcheck

favicon staticcheck.io
Collapse
 
codypotter profile image
Cody Potter

After reading that SO post, there are good arguments on both sides here. The accepted answer is anti-self, but the best argument that it puts forth is that we can attach methods to all kinds of types. IMO it COULD be a little funny to refer to a slice type as self depending on the context. However, another answer put forth another great argument.

Using self or this conveys that the function is an instance method. Every programmer immediately recognizes that it is referring to the instance it is attached to. Consistency across a codebase contributes to clarity and ease of understanding. Adding yet another custom variable name to a scope increases complexity. If the language reserved a keyword for the receiver, this complexity would be removed.

I hear a lot of folks say that we shouldn’t use this because the receiver behaves differently than other languages. I’d argue that every programming language has idiosyncracies. Just because the receiver behaves differently, we can’t also conclude that the name self is off limits as a result. Gophers know that receivers behave differently.

Arguing that we shouldn’t use self or this because of a linter’s rules or the language wiki’s preference is a not a strong argument. That’s just someone else’s opinion. I think listening to experts is a great practice and generally aligns you with the safe majority, but in this case, I’m making an argument against the majority.

Thanks again for contributing!

Thread Thread
 
ccoveille profile image
Christophe Colombier

I agree with you. I was unable to find an acceptable explanation.

People are somehow rephrasing the text provided by the official documentation

Collapse
 
codypotter profile image
Cody Potter

Thanks for contributing to the conversation. I’ll check this stuff out.