Skip to content

spec: add generic programming using type parameters #43651

Closed

Description

@ianlancetaylor

We propose adding support for type parameters to Go. This will change the Go language to support a form of generic programming.

A detailed proposal document has been published, with input from many members of the Go community. We are now taking the next step and proposing that this document become a part of the language.

A very high level overview of the proposed changes:

  • Functions can have an additional type parameter list that uses square brackets but otherwise looks like an ordinary parameter list: func F[T any](p T) { ... }.
  • These type parameters can be used by the regular parameters and in the function body.
  • Types can also have a type parameter list: type MySlice[T any] []T.
  • Each type parameter has a type constraint, just as each ordinary parameter has a type: func F[T Constraint](p T) { ... }.
  • Type constraints are interface types.
  • The new predeclared name any is a type constraint that permits any type.
  • Interface types used as type constraints can have a list of predeclared types; only type arguments that match one of those types satisfy the constraint.
  • Generic functions may only use operations permitted by their type constraints.
  • Using a generic function or type requires passing type arguments.
  • Type inference permits omitting the type arguments of a function call in common cases.

For more background on this proposal, see the recent blog post.

In the discussion on this issue, we invite substantive criticisms and comments, but please try to avoid repeating earlier comments, and please try to avoid simple plus-one and minus-one comments. Instead, add thumbs-up/thumbs-down emoji reactions to comments with which you agree or disagree, or to the proposal as a whole.

If you don't understand parts of the design please consider asking questions in a forum, rather than on this issue, to keep the discussion here more focused. See https://golang.org/wiki/Questions.

Activity

  1. added this to the Proposal milestone on Jan 12, 2021
  2. atdiar commented on Jan 12, 2021

    @atdiar
  3. ALTree commented on Jan 12, 2021

    @ALTree
  4. atdiar commented on Jan 12, 2021

    @atdiar
  5. hanneshayashi commented on Jan 12, 2021

    @hanneshayashi
  6. tsal commented on Jan 12, 2021

    @tsal

    Why any and not interface{} ?

    an interface{} wouldn't make sense here since we're describing a generic trait that needs to be implemented. This is more meta-code and interface{} is still concrete - even if it is "generic" in some senses of the word.

    I'm also having trouble thinking how you could implement any interface{} generic parameters, since you don't know what the interface will actually be - and if you're doing interface type-checking here, it's defeating the entire point of generics (IMO).

  7. coder543 commented on Jan 12, 2021

    @coder543
  8. bcmills commented on Jan 12, 2021

    @bcmills
    Contributor

    I remain concerned that this proposal overloads words (and keywords!) that formerly had very clear meanings — specifically the words type and interface and their corresponding keywords — such that they each now refer to two mostly-distinct concepts that really ought to instead have their own names. (I wrote up this concern in much more detail last summer, at https://github.com/bcmills/go2go/blob/master/typelist.md.)


    Specifically, the word type today is defined as:

    A type determines a set of values together with operations and methods specific to those values.

    Under this proposal, I believe that a type would instead be either a set of values with operations, or a set of sets of values, each with its own set of operations.

    And today the word interface, in the context of Go, refers to a type, such that:

    A variable of interface type can store a value of any type with a method set that is any superset of the interface.

    Under this proposal, a variable of interface type can store a value of any type with a method set that is any superset of the interface, unless that interface type refers to a set of sets of values, in which case no such variable can be declared.


    I'd like to see more detail on the exact wording proposed for the spec, but for now I am against this specific design, on the grounds that the ad-hoc overloading of terms is both confusing, and avoidable with relatively small changes in syntax and specification.

  9. flibustenet commented on Jan 12, 2021

    @flibustenet
    func foo[T Stringer](t T) string {
    	return t.String()
    }
    func foo(t Stringer) string {
    	return t.String()
    }

    The difference are very subtil. How will you document the best practice when a Go1 interface is enough ?
    I mean, how to prevent abuse of generic when both can be used ?

  10. nadiasvertex commented on Jan 12, 2021

    @nadiasvertex
    Contributor

    Would still prefer to have the empty interface. How tedious can this really be? Especially since we can define type aliases ourselves...

    I think interface{} is a mistake. It is a hack to permit something like void * without any semantic cues to help a user understand what is going on. I would have preferred to have "any" as a type in the language from the beginning, even it it was just an alias for interface{} under the covers.

    Of course, the new "any" is different than interface{}. It would be nice to have a named type that means "any type by reference" instead of "any type by substitution".

  11. michaelwilner commented on Jan 12, 2021

    @michaelwilner
    ```go
    func foo[T Stringer](t T) string {
    	return t.String()
    }
    func foo(t Stringer) string {
    	return t.String()
    }

    The difference are very subtil. How will you document the best practice when a Go1 interface is enough ?
    I mean, how to prevent abuse of generic when both can be used ?

    Valid point, in your example, an interface would be the better choice. However, a more apt use case of generics would be sort. Operations on slices of arbitrary types would be distinctly less verbose with generics as compared to interfaces. This talk touches on some of the points: blog.golang.org/why-generics (disclaimer: syntax in this link is different than this generics proposal, but the points are useful to draw comparison)

  12. JeremyLoy commented on Jan 12, 2021

    @JeremyLoy

    What are the plans for amending the standard library to utilize generics? I see two important tracts of work here.

    1. retroactively applying generics to packages like sort, container/list
    2. Creating new packages and libraries that were previously cumbersome without generics; i.e. mathematical set functions,
  13. coder543 commented on Jan 12, 2021

    @coder543

    @bcmills

    Specifically, the word type today is defined as:

    A type determines a set of values together with operations and methods specific to those values.

    That sentence describes a struct. An interface is also a kind of type in Go, and it does not determine the set of values or operations that are present, only the set of methods.

    The fact that a type is not just a struct is why the syntax in the language is type foo interface { ... }, type foo struct { ... }, and even type foo bar or type foo = bar.

    A generic type is just as concretely a set of values, operations, and methods as an interface is (which is to say, you an argue that it isn't). So either we should redefine interface to not be a type (by the definition you're quoting), or we should accept that a generic type is also a type, just one that requires type parameters to be resolved before it becomes a concrete type.

    If the proposal is misusing the term "type" in place of "type parameter" anywhere, I think that could be valid criticism... but it sounds like you're criticizing some ambiguous/arguably wrong terminology that exists in the Go language spec, which is terminology that is refuted by the language itself, as demonstrated by Go syntax above. If an interface is not a type, we should not prefix the declaration with the word type, but we do.

    That whole area of discussion seems off topic here, and clarifications to the existing language spec could be proposed somewhere else? I've read through the generic proposal several times and I haven't come away feeling like the terminology used was ambiguous or confusing, and your statements here do not effectively make the case for that either, in my opinion.

  14. fzipp commented on Jan 12, 2021

    @fzipp
    Contributor

    Of course, the new "any" is different than interface{}.

    The new "any" is not different from interface{} as a type constraint. [T any] and [T interface{}] are interchangeable as per the proposal.

  15. 440 remaining items

  16. m-ivanov commented on Feb 20, 2021

    @m-ivanov
  17. billinghamj commented on Feb 20, 2021

    @billinghamj
  18. GoldsteinE commented on Feb 20, 2021

    @GoldsteinE
  19. rsc commented on Feb 20, 2021

    @rsc
    Contributor

    In #43651 (comment) I wrote

    No change in consensus, so accepted. 🎉
    This issue now tracks the work of implementing the proposal.
    — rsc for the proposal review group

    That is our usual way of using issues, but this issue continues to gather comments that are not relevant to tracking the work of implementing the proposal. Honestly, that was probably inevitable and understandable. But it's no longer the place for comments and questions about the proposal itself.

    I'm going to lock this issue and close it. We won't forget about the implementation without a tracking issue, I promise.

  20. locked as off topic and limited conversation to collaborators on Feb 20, 2021
  21. gopherbot commented on Mar 19, 2021

    @gopherbot
    Contributor

    Change https://golang.org/cl/303389 mentions this issue: design: promote type parameters to a proposal

  22. gopherbot commented on Apr 1, 2021

    @gopherbot
    Contributor

    Change https://golang.org/cl/306689 mentions this issue: design: update type parameters design for type sets

  23. gopherbot commented on Aug 20, 2021

    @gopherbot
    Contributor

    Change https://golang.org/cl/343732 mentions this issue: cmd/compile: enable -G=3 by default

  24. moved this to Accepted in Proposalson Aug 10, 2022
  25. removed this from Proposalson Oct 19, 2022
  26. modified the milestones: Backlog, Go1.18 on May 30, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions