Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

proposal: Go 2: remove redundant struct specifier on methods declarations #29459

Closed
HaySayCheese opened this issue Dec 29, 2018 · 8 comments
Closed
Labels
FrozenDueToAge LanguageChange Proposal v2 A language change or incompatible library change
Milestone

Comments

@HaySayCheese
Copy link

HaySayCheese commented Dec 29, 2018

The standard way to declare the method for some struct is the next:

type SomeStruct struct {
    someArg interface{}
}

func (s *SomeStruct) somePointerBasedMethod() {}

func (s SomeStruct) someValueBasedMethod() {}

If there are only few methods in the struct - it is ok, but if you have relatively big collection of methods - duplication of the struct specifier goes boring very quickly. For the structures which names are long - the problem goes further and significantly increases the code base size and decreases readability, for example:

type SomeVeryLongNameStructWithComplexLogic struct {
    someArg interface{}
}

func (s *SomeVeryLongNameStructWithComplexLogic) somePointerBasedMethod() {}

func (s SomeVeryLongNameStructWithComplexLogic) someValueBasedMethod() {}

The proposal is to simplify the syntax to the next way:

type SomeStruct struct {}

// Method of struct "SomeStruct", 
// because it is first struct reached on the direction 
// from the method declaration to the beginning of the file.
//
// 99% of code is written in the manner when struct-related methods 
// are going right after the related struct. There is no need for huge code duplication.
//
// "*s" after keyword `func` automatically specifies that method's receiver is a pointer.
// At the same time it names the receiver to "s".
func *s somePointerMethod() {
    s.someArg = noop()
} 

// For value based receivers - there is the same logic.
func s someValueMethod() {
    s.someArg = noop()
}

The presence of an argument between the keyword func and the method's name automatically indicates that this method belongs to the struct. We do not need any parentheses or redundant struct names specified.

With this improvement the code for long named structs would look like this:

type SomeVeryLongNameStructWithComplexLogic struct {}

func *s someMethod() {}

func *s someOtherMethod() {}

The code for the cases when there are several structs defined in common file:

type StructA struct {}

func *s method() {}

func *s other() {}

// etc ...

type StructB struct {}

func *s method() {}

func *s other() {}

One more important thing here is the potential performance boost.
Compiler would be able to identify corresponding struct significantly faster with this syntax, because it would be able to simply store the last seen struct and attach all methods seen further to it automatically. No more any receiver's name parsing needed.

@gopherbot gopherbot added this to the Proposal milestone Dec 29, 2018
@crhntr
Copy link

crhntr commented Dec 30, 2018

Code I contribute to often has long type names (on the order of the example) and writing them over again is not a big issue (vim-go or other editor plugins help). I think the added syntactic sugar shown above doesn't provide much value for the cost of having two ways to write the same thing.

@mvdan
Copy link
Member

mvdan commented Dec 30, 2018

This would also add ambiguity to the language syntax. When the parser sees func foo, does it:

  • parse foo as a function name, e.g. func foo() { ... }
  • parse foo as this new receiver syntax, e.g. func foo bar() { ... }

Go has very few ambiguities like those at the moment, so I think we should be very careful when adding more.

Another point against this change that I see is that we already have the func (foo) bar() { ... } form, but it means a different thing - in there, foo is the receiver type, not name. I think this syntax would complicate the language for readers. Remember that Go should be easy to read and understand, not so much to write quickly.

@ianlancetaylor ianlancetaylor changed the title proposal: remove redundant struct specifier on methods declarations proposal: Go 2: remove redundant struct specifier on methods declarations Dec 30, 2018
@ianlancetaylor ianlancetaylor added the v2 A language change or incompatible library change label Dec 30, 2018
@ianlancetaylor
Copy link
Contributor

For the record: since any type can have methods, this should clearly apply to any type, not just struct types. (But I think it is unlikely that we would adopt this change.)

@HaySayCheese
Copy link
Author

HaySayCheese commented Dec 30, 2018

@mvdan

This would also add ambiguity to the language syntax. When the parser sees func foo, does it

Actually no.
The parser should only check where the token with parentheses appears (the name of the function) and then check if there is a receiver defined before it. This is very transparent logic. There is no ambiguity here.

@crhntr

vim-go or other editor plugins help

As I know, golang tries to be tool-independent.
It is great that many editors has support for this kind of code duplication problem, but from the language perspective it seems to be wrong solution.

On early days of the language the core team declared that even code highlighting would be not needed for the golang due it's tiny and well composed syntax. My proposal follows the idea that language should be simple for writing and reading without any kind of additional tools.

Another point here is the next: in case if this kind of syntax was introduced by the language reasonable earlier, what kind of 2 types to write methods of structs would you choose today: shorter or longer?

@HaySayCheese
Copy link
Author

@mvdan

Another point against this change that I see is that we already have the func (foo) bar() { ... } form, but it means a different thing - in there, foo is the receiver type, not name. I think this syntax would complicate the language for readers.

In this case foo is wrapped by the parentheses, and it clearly indicates, that it is not a receiver. There is no mental collision here.

Remember that Go should be easy to read and understand, not so much to write quickly.

Agree that "Go should be easy to read and understand".
And code base shortening seems to be the good way to reach it.
Less code to read == less time for mental processing, no?

@mvdan
Copy link
Member

mvdan commented Dec 30, 2018

This is very transparent logic. There is no ambiguity here.

The parser should know how to parse a top-level declaration just by looking at each token. Remembering earlier type declarations, and peeking at tokens to see if there's an open parentheses, is precisely what would make the Go syntax much more complex. Just from looking at func foo it's completely ambiguous what the parser should do, as I explained above.

There is no mental collision here.

Your new proposed syntax is very similar to an existing syntax that does something very different - I'm only pointing that out.

And code base shortening seems to be the good way to reach it.

We agree to disagree. Languages that try to be fast to write by saving characters at all costs tend to be the less readable ones in the long run.

@bitfield
Copy link

bitfield commented Jan 5, 2019

This would certainly make readability worse, in exchange for the dubious benefit of saving a few keypresses when typing code. A non-starter, in my view.

@ianlancetaylor
Copy link
Contributor

Currently all Go top level declarations are stand alone. This would break that feature. It would mean that introducing a new type definition between existing methods could completely break the program.

The resulting code seems less readable.

This means that either you can't move a method declaration to a different file, or there are two different syntaxes for method declaration which seems like unnecessary duplication.

If the concern is long type names for readability, you can always use an alias for the method declarations.

Thanks, but we aren't going to make this change.

@golang golang locked and limited conversation to collaborators Jan 15, 2020
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
FrozenDueToAge LanguageChange Proposal v2 A language change or incompatible library change
Projects
None yet
Development

No branches or pull requests

6 participants