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: Make Generics usage more accessible #39331

Closed
ankitbko opened this issue May 31, 2020 · 2 comments
Closed

Proposal: Go 2: Make Generics usage more accessible #39331

ankitbko opened this issue May 31, 2020 · 2 comments
Labels
FrozenDueToAge generics Issue is related to generics LanguageChange Proposal v2 A language change or incompatible library change
Milestone

Comments

@ankitbko
Copy link

ankitbko commented May 31, 2020

So I am very new to Go (literally started learning day before yesterday) before I stumbled upon lack of generics and years of discussion over it. It would take me days and probably months to catch up to all the discussions and proposals.

So I am writing this without knowing if this has already been discussed and also without knowing full history of go. I am also not sure if this is right place (and right mode) to make this suggestion, there are just so many proposals, blogs, discussions scattered around multiple places.

I have only read this blog on generics and based on that I have below suggestion -

Have we considered using some other syntax instead of parenthesis ( and ) to define generics?

Why?

Because parenthesis are used to pass arguments to a function and it gets confusing if used to define generic type specially because its used just before actual arguments.

For example here is the generic Reverse function example from the blog -

func Reverse (type Element) (s []Element) {
    first := 0
    last := len(s) - 1
    for first < last {
        s[first], s[last] = s[last], s[first]
        first++
        last--
    }
}

func ReverseAndPrint(s []int) {
    Reverse(int)(s)
    fmt.Println(s)
}

Focus on Reverse(int)(s). This looks all good. But what happens if its like this Reverse(foo)(s). Well by just reading this line I can't make out whether foo is a type or a variable defined somewhere above in my program.

Reverse could now be a function that returns a function which takes another parameter (func Reverse(a int) func([]int) int) and foo can just be an integer defined somewhere above (don't go into integrities of why Reverse will accept int, that is not the point, this is just to demonstrate). To understand which it is I have to either scan through my code to know what foo is or go to the definition of Reverse function.

The point is that this is not ambiguous to compiler but it is to the user. At first glance it is not clear what it is and user will have to pay special attention to it.

Another similar example of hard to read is func Reverse (type Element) (s []Element). The first time I read it I thought Reverse is a function which has a parameter called type of type Element and returns a named value s of type []Element. Why because I had just completed the golang tour which has very similar looking split function. It was only when I read it second time that I noticed that type is a reserved word and cannot be the parameter name.

Again this is not problem for compiler but user has to pay special attention here not to misunderstand. I know the IDE will probably do correct syntax highlighting and make it more obvious is both the cases but still this is not something language should depend upon.


I know this may not be a problem with everyone and others would have more attention to detail. But since I faced it I thought to have a discussion on potential improvement in this.

The proposal is to make the generics visually distinct from parameters/argument. Generics are used just before parameters/arguments and so should look different from them so when scanning through a code I don't have to pay special attention to distinguish between them.

A potential solution could be to use angle bracket for generics < >.

So the above example would become -

func Reverse <Element> (s []Element) {
...
}

func ReverseAndPrint(s []int) {
    Reverse<int>(s)
}

Why angle brackets?

  • I haven't seen them used at that position in go so its visually distinct.
  • A lot of language (c#, java, c++, typescript etc) use angle brackets for generics so majority of developers around the world are in habit (and muscle memory) of using angle brackets for generics. Its almost encoded in brain that things between angle bracket in function definition and usage relates to generic. It will also be easier for new gophers to get started as this may be similar syntax to what they are used to.

I love the fact how Go is designed to be easy to use. All the features, syntax, concepts are orthogonal which makes it really easy to both read and write Go code.

@gopherbot gopherbot added this to the Proposal milestone May 31, 2020
@martisch
Copy link
Contributor

martisch commented May 31, 2020

Currently the focus seems still on finalizing semantics before going into details and iterating on syntax.
To quote @ianlancetaylor from similar proposals like: #36457

Please also feel free to add a link to this issue to https://github.com/golang/go/wiki/Go2GenericsFeedback. We don't think it will be helpful to keep multiple generics syntax issues open simultaneously, spreading the discussion to too many different places.

There is also dicsussions continuing on at #15292.

Using <...> for type parameters has come up multiple times and has its own problems see e.g.: #15292 (comment) and following.

@ianlancetaylor ianlancetaylor added generics Issue is related to generics v2 A language change or incompatible library change LanguageChange labels May 31, 2020
@golang golang locked and limited conversation to collaborators May 31, 2021
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
FrozenDueToAge generics Issue is related to generics LanguageChange Proposal v2 A language change or incompatible library change
Projects
None yet
Development

No branches or pull requests

5 participants