Go: proposal: Go 2: add receiver shortcut (default this/self)

Created on 11 May 2018  ·  8Comments  ·  Source: golang/go

Currently the method receiver needs to be explicitly specified when it's used, whether it's for calling another method of the receiver or accessing struct fields.

My proposal is to allow the receiver name be omitted, either completely or by using only a dot.

Let's assume I have a method:

func (obj *MyObject) MyMethod() {
  obj.anotherMethod()
  // more code
}

I could then simply use anotherMethod() or, if we're afraid of shadowing, let's keep the dot and use .anotherMethod().

The only rationale behind the idea is to omit the often-repeated name and slightly shorten the code.
As far as I can see (not far, admittedly), this could be incorporated in Go2 or even Go1.

FrozenDueToAge Go2 LanguageChange Proposal

Most helpful comment

Not just the spirit, but the idea that every identifier's origin is easy to find just by looking at it, without parsing and other complexities. Type aliases complicated that somewhat but they are, sadly, a necessary evil. Otherwise, when I see x.Y I know that if I find the declaration for x, I will know what Y is, and that x is an identifier defined in this package. If I see a bare Y, I know that Y is itself defined as a top-level name in this package.

Your proposal breaks that property and should be rejected.

All 8 comments

I suggest this is a problematic idea for many of the same reasons that dot imports are discouraged.

More details https://groups.google.com/forum/m/#!topic/golang-nuts/XCNzIfM4VmU

This will hurt readability. Go emphasizes clarity and readability over terseness. And in most cases, a receiver is just 1 to 3 characters long anyways. So IMO, it's not worth it.

```Go
func Do() { ... }

type T struct { ... }

func (t *T) Do() { ... }

func (t *T) M() {
// Which Do is called?
// There is an answer, but it seem sure to be confusing to readers.
// Is the benefit worth the cost?
Do()
}

Omitting it completely will definitely hurt readability and introduce a bunch of problems that other languages have to deal with because of the ability to omit this/self.

Why not instead introduce mandatory this/self when the name of the receiver is omitted? Like so:

func (*MyObject) MyMethod() {
  this.anotherMethod()
  // more code
}

This has two advantages:

  1. You no longer have to come up with a name for the receiver. Naming things is always hard
  2. Future readers wouldn't have to guess, what it is when they see f.Foo(). Is it local or global variable, name of a package or the receiver? You see this.Foo() and instantly understand what it is.

Obvious disadvantage is it introduces a new keyword. Don't known how context aware Go compiler is and will it be a major problem.

Regarding shadowing caveat: that's why I also suggested an alternative dot-syntax .anotherMethod() to avoid problems here.

Regarding readability: actually I consider short receiver names a bit harmful since they tend to lose the context, what is a good receiver name below? If it's usually self, this or me it does not add much to readability. If it's something longer (washer perhaps) then the code becomes a bit too verbose for my taste.

func (self *WashingMashineImpl) Wash() {
  self.checkPreconditions()
  self.heatTheWater()
  // more code
}

I like the direction suggested by @creker, removing the receiver name altogether solves the above problem for me. Instead of introducing this I'd simply stay with dot notation though, to avoid an extra keyword. If easy parsing is important than maybe we can use underscore instead of the name though to my eyes it's not too pretty: _.anotherMethod().

But based by the initial reaction I guess the suggestion is not really in the spirit of go language.

Not just the spirit, but the idea that every identifier's origin is easy to find just by looking at it, without parsing and other complexities. Type aliases complicated that somewhat but they are, sadly, a necessary evil. Otherwise, when I see x.Y I know that if I find the declaration for x, I will know what Y is, and that x is an identifier defined in this package. If I see a bare Y, I know that Y is itself defined as a top-level name in this package.

Your proposal breaks that property and should be rejected.

There are of course fewer places in Go where some expression doesn't need "other complexities", but selector expressions, for example, can mean many things.
Methods expressions (Type.Method), fully-qualified names (idents from other packages), field access. And method invocations that can be either "real method" call or access for function-type struct member with invocation (for example: v.f() can mean more than one thing).

So there are some places that violate the idea described above, but it doesn't mean more of such features are desired.

We aren't going to do this, even in Go 2.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

myitcv picture myitcv  ·  3Comments

jayhuang75 picture jayhuang75  ·  3Comments

rsc picture rsc  ·  3Comments

natefinch picture natefinch  ·  3Comments

michaelsafyan picture michaelsafyan  ·  3Comments