Skip to content

spec: generic methods for Go #77273

Closed
1 of 1 issue completed
Closed

Description

@griesemer

Proposal: Generic Methods for Go

A change of view.

Background

For clarity, in the following we use the term concrete method (or just method when the context is clear) to describe a non-interface method declared like a function but with a receiver; and we use the term interface method to describe the name and signature of a method of an interface.

Per the current spec, a concrete method is a function with a receiver. Syntactically this is not quite true: while functions can be generic, methods cannot. They cannot declare new type parameters themselves; but they can have a receiver of a generic type (and thus have method-local names for the type parameters of the receiver type).

A reason for this discrepancy is that we have historically viewed the primary role of methods as a means to implement an interface: permitting type parameters on concrete methods would imply that we must also permit type parameters on interface methods. Go doesn't support such generic interface methods because we don't know how to implement (calls of) them, or at least we don't know how to implement them efficiently. Specifically, because Go doesn't require a concrete type to declare the interfaces it implements, and instead this is a dynamic property, it cannot be known at compile time which of the infinite possible instantiations of concrete methods will be needed at run time. This shortcoming has long been known and was discussed at length in the original Type Parameters Proposal.

But concrete methods are not just a means for implementing interfaces. A method is a function associated with a type, and accessed through the namespace of that type. Therefore methods are useful for organizing code even if they don't ever implement an interface. Furthermore there is a syntactic benefit: x.a().b().c() may naturally be read left to right, whereas c(b(a(x))) is evaluated inside out. Both these aspects of methods are also well known.

For these reasons, Go users have requested generic methods for a long time and the idea is widely popular. There are at least two proposals filed on the issue tracker:

  • #49085 (Allow type parameters in methods, Oct. 2021, with > 900 positive emojis)
  • #50981 (Add generics to methods, Feb. 2022)

So far we have resisted adding generic concrete methods because it always implied that we also needed generic interface methods. The Go FAQ even states that "we do not anticipate that Go will ever add generic methods". Perhaps a change of view is in order: concrete methods are a language feature that is useful in itself, irrespective of interfaces. If a concrete method is a function with a receiver, a generic concrete method can be a generic function with a receiver. The fact that such methods may not be invoked via an interface is an orthogonal aspect: if an interface syntactically can’t include a method with type parameters, then a generic concrete method naturally plays no role in satisfying that interface because there can’t be an interface method with matching type parameters.

Note that the original Type Parameters Proposal discussed this alternative view as well, as expressed in the following paragraph:

"Or, we could decide that parameterized methods do not, in fact, implement interfaces, but then it's much less clear why we need methods at all. If we disregard interfaces, any parameterized method can be implemented as a parameterized function."

We may have reached some clarity on this point: generic concrete methods are useful by themselves, even if they don't implement interface methods.

Proposal

We propose that concrete method declarations should look exactly like function declarations, but with receivers. Specifically, the syntax of a method declaration should accept type parameters as do function declarations. The syntax of function declarations is as follows:

FunctionDecl = "func" FunctionName [ TypeParameters ] Signature [ FunctionBody ] .

The syntax of method declarations should be changed from (old):

MethodDecl = "func" Receiver MethodName Signature [ FunctionBody ] .

to (new):

MethodDecl = "func" Receiver MethodName [ TypeParameters ] Signature [ FunctionBody ] .

Alternatively, to the same effect, the syntax can express directly what we say in prose: a method (declaration) is a function (declaration) with a receiver, and combine the two productions. This removes a syntax production and emphasizes the similarities:

FunctionDecl = "func" [ Receiver ] identifier [ TypeParameters ] Signature [ FunctionBody ] .

The scope of an identifier denoting a type parameter of a generic method begins after the name of the method and ends at the end of the method body. This matches existing rules for type parameters of functions and method receivers. Constraints for method type parameters may refer to type parameters declared with the method receiver because they are in scope.

Calling a generic concrete method works as expected: either, type arguments are provided as needed, or type inference determines any missing type arguments, exactly like for generic function calls.

Method expressions and method values continue to work as expected: if the method is generic, the resulting function is generic and the existing rules for using generic functions apply.

The grammar will need a small adjustment: currently type arguments may only be supplied to operand names which are (possibly package-qualified) identifiers for generic functions and types. Per the syntax for operands (old):

Operand     = Literal | OperandName [ TypeArgs ] | "(" Expression ")" .  
…  
OperandName = identifier | QualifiedIdent .  
TypeArgs    = "[" TypeList [ "," ] "]" .

Methods can be attached to arbitrary user-defined types, and values of such types may be denoted by various expressions, not just qualified identifiers. To permit instantiation of generic methods, type arguments must move from the syntax for operands to the syntax for primary expressions, resulting in the updated productions (new):

Operand     = Literal | OperandName | "(" Expression ")" .

PrimaryExpr = Operand |
              Conversion |
              MethodExpr |
              PrimaryExpr Selector |
              PrimaryExpr Index |
              PrimaryExpr Slice |
              PrimaryExpr TypeAssertion |
              PrimaryExpr Arguments |
              PrimaryExpr TypeArgs .

(Notably, type arguments are already parsed as part of primary expressions in the current implementation. This is necessary because an instantiation such as T[int] and an index expression a[i] are syntactically indistinguishable. In the language specification, the syntactic overlap between these two is maintained solely for the sake of documentation.)

Methods of interfaces are not changed. Importantly, a generic concrete method does not match against an interface method with the same name and signature because the interface method syntactically cannot have matching type parameters.

Generic methods also won't be accessible via reflection (by name or index) for the same reason that uninstantiated generic functions are not accessible: the reflect package doesn't have a mechanism to instantiate a generic value or type (and it is unclear how one would provide such a mechanism).

This is the entirety of the proposal.

Examples

Given a (non-interface) receiver base type S, we may associate a generic method m with it:

type S struct { … }  
func (*S) m[P any](x P) { … }

Given a variable s of type S (or a value of type *S), we can call m as follows:

var s S  
s.m[int](42)    // explicit type argument int  
s.m(x)          // type argument P is inferred from x

A receiver base type may itself be generic:

type G[P any] struct{ … }  
func (*G[P]) m[Q any](x Q) { … }

Calling m requires a variable whose type is an instantiation of G, but there is no other difference in the way m is called.

An interface I with a method m:

type I interface {  
	m(string)  
}

may be implemented by a suitably instantiated generic type G (this is true in current Go):

type G[P any] struct{ … }  
func (G[P]) m(P) { … }

var g G[string]  
var _ I = g		// valid because G[string].m has signature m(string) which matches m(string) of I

But I is not implemented by a type H with a generic method m:

type H struct{ … }  
func (H) m[P any](P) { … }

var h H  
var _ I = h		// invalid because H.m has signature m[P any](P) which doesn't match m(string) of I

Here's another, less abstract example, related to the Go library. A Reader type with a generic Read method:

type Reader struct{ … }  
func (*Reader) Read[E any]([]E) (int, error) { … }

does not implement io.Reader, even though it might if there were some way to instantiate the method as (*Reader).Read[byte] (which there is not, and we are not proposing it).

Method expressions (and method values) work as expected. Given the Reader type from above, the method expression Reader.Read produces a generic function with type parameters and signature:

[E any](*Reader, []E) (int, error)

If the type itself is generic, it must be instantiated (per existing Go rules for generic types) before it can be used in a method expression. For instance, given a generic List type with a generic formatting method format:

type List[E any] struct { … }  
func (*List[E]) format[F any](E, F) string { … }

the method expression List[string].format will result in a function with type parameters and signature

[F any](string, F) string

In particular, List.format is not a valid method expression (List is not instantiated), nor does it produce the generic function signature

[E any, F any](E, F) string	// not the signature of List.format

Implementation

Specification

The change to the language specification is small and fully backward-compatible. The syntax changes have been outlined above. The corresponding prose changes are similarly straightforward.

Whenever there is a language change, updating the specification is a tiny part of the work needed to get documentation updated in general. This includes existing documents traditionally maintained by the Go team (which we plan to keep fresh as much as possible), to 3P documentation beyond our control (external blog post, articles, books, etc.). These will become partly out of date and may or may not be updated, but that is not avoidable if we want to make changes to the language.

Compiler

The parser already accepts type parameters for methods for robustness but complains with an error. Removing that error is a trivial change. The parser also already handles index expressions and instantiations together. If any changes are needed at all, they will be minimal. The type checker will need various adjustments, most likely involving the removal of restrictions, the details of which will only become apparent by doing the actual work.

The compiler back-end changes are likely more significant. That said, method calls via non-interface receivers can be resolved statically (at compile time): because the type of the receiver is not an interface, its type is statically known, and thus the called method is also statically known. Conceptually, such method calls can be rewritten into function calls. If the method itself is generic, the method call can be rewritten into a call of a corresponding generic function.

For instance, given the type G, method m, and instance x of G:

type G[P any] struct{ … }  
func (G[P]) m[Q any](x Q) { … }

var g G[string]

the method call

var s string  
g.m(s)

can be translated into a function call f(s) of the generic function

func f[Q any](g G[string], x Q) {  
	G[string].m[Q](g, x)		// using a call of method expression G[string].m  
}

or

func f[Q any](g G[string], x Q) {  
	g.m[Q](x)			// using a call of method value g.m[Q]  
}

This is not to say that an implementation will be trivial. But the principal translation mechanism is understood.

The import/export data format will need to be updated to allow for type parameters on methods. This is likely the most disruptive change because of the many different exporters and importers that exist, some of which are used for language tools, reside in different repositories, and all must remain in sync with the compiler's export format. Carefully staged updates are needed in order to not break existing infrastructure. We have done import/export data format changes in the past, and while tedious, they can be done.

Libraries and tools

No change of the existing libraries is required, but future (versions of these) libraries may want to use generic methods.

The impact on tools may be significant as they will need to handle the new language feature. The go/types API's Signature type already provides accessors for receiver and ordinary type parameters, so it's possible that no API changes are needed there, but go/types clients cannot rely on the (current) fact that only one of type parameter lists is present. Judging from past experience, it may take one or two release cycles for all tools to catch up. It is difficult to judge the amount work involved without actually doing the work.

Other considerations

This proposal adds a new feature to the language by removing a restriction; thus it is fully backward-compatible with existing Go. Importantly, it also doesn't preclude the implementation of generic interface methods at some point, should we find an acceptable implementation solution that doesn't impose a cost when the feature is not used.

Generic functions and types make it possible to write more complex code and adding generic methods will further increase that capability. But used appropriately, generic methods can simplify and generalize situations where currently more complex work-arounds are needed (see #49085 for an example).

Activity

  1. added this to the Proposal milestone on Jan 22, 2026
  2. mpx commented on Jan 23, 2026

    @mpx
    Contributor

    Perhaps an extension could be considered (initially or later) to enable declaring specific concrete methods should exist and be available for interfaces. Eg:

    type Reader struct{ … }  
    func (*Reader) Read[E any]([]E) (int, error) { … }
    
    // Specify the Read method should exist for "byte"
    func (*Reader) Read[byte]([]byte) (int, error)
    
    // Now works
    var r = io.Reader(&Reader{})

    In some ways this is similar to declaring functions where the body is implemented elsewhere.

    There may be challenges around specifying an unambiguous syntax (I haven't thought it through here). I don't have a strong opinion on the actual syntax - but it would be useful if it was possible.

  3. mpx commented on Jan 23, 2026

    @mpx
    Contributor

    I think proposal would be very useful - no initial concerns. However, an observation on terminology. Some might find concrete method confusing since they may assume all the type arguments are known when they hear the term (bundling the concepts mentally - an invalid shortcut AIUI).

  4. doggedOwl commented on Jan 23, 2026

    @doggedOwl

    This is very much needed. It's the missing piece to the Go's Implementation of Generics.
    Methods are a very important way of code organisation, not just a way to implement Interfaces.

  5. AGWA commented on Jan 23, 2026

    @AGWA

    👍 math/rand/v2.Rand is an example of a type whose methods are not for implementing interfaces, and which would benefit from this proposal, as it's currently missing a method equivalent of the generic N function - the only function in the package that lacks a method equivalent in Rand.

  6. gopherbot commented on Jan 23, 2026

    @gopherbot
    Contributor

    Change https://go.dev/cl/738441 mentions this issue: cmd/compile/internal/syntax: enable generic method syntax in parser

  7. Merovius commented on Jan 23, 2026

    @Merovius
    Contributor

    I have no strong opinions on this proposal. I think it works and its benefits and downsides are mostly well-understood - whether it is a good addition thus comes down to subjective opinion. I just have one nit about the proposal text:

    if an interface syntactically can’t include a method with type parameters, then a generic concrete method naturally plays no role in satisfying that interface because there can’t be an interface method with matching type parameters.

    This applies to the idea of having generic methods in interfaces, but it doesn't apply to the idea of generic methods implementing non-generic methods in interfaces (the io.Reader case mentioned).

    I agree that if we want generic methods, the proposed semantics are right¹, but I predict that this will become one of the most frequently asked questions related to generics. We should explicitly call that out in documentation.

    I also think people underestimate the importance of having generic methods in interfaces for the use cases they have in mind, so I think that most people who are currently requesting generic methods will shift to requesting getting generic methods in interfaces as well, but the proposal text already acknowledges that.

    [1] As to @mpx suggestion of explicitly instantiating methods: I don't like this idea either syntactically or semantically. Syntactically, functions without bodies are a very rare thing, so I don't think the analogy is helpful to most people. And replacing [T any] with [byte] as an indicator is too problematic because of the already confusing way this works in generic receivers: one of the most common questions we get is that people try to do this (have a generic type X[T any] … and then write a method func (X[byte]) M()) with the expectation that this will imply a refined method constraint. To me, this indicates that people's expectation of what this syntax means would differ from what it would do.

    Semantically, it just doesn't seem to fit well into a language which uses structural typing for interfaces in general.

  8. jub0bs commented on Jan 23, 2026

    @jub0bs
    Contributor

    This is exciting! I'm overall in favour of this proposal. How soon can we start playing with an implementation?

    However, I also have some concerns:

    1. How easy will this new subtlety (concrete methods can introduce type params, but interface methods cannot) to teach?
    2. Would this new functionality be released gradually, perhaps initially behind a GOEXPERIMENT flag? (I think it should.)
    3. There are proposals to allow tightening constraints in methods on generic types (e.g. proposal: spec: allow methods on generic structs which meet subset of type constraint #65394 and proposal: spec: allow additional constraints on methods of generic types #64846). I believe this is what @Merovius calls refined method constraints. Such functionality is, IMO, also desirable. Is this proposal orthogonal enough as to leave the door open for refined method constraints further down the road? My impression is that the answer is "yes", but I'd like to hear it from @griesemer. 😇
  9. sudomateo commented on Jan 23, 2026

    @sudomateo
    • How easy will this new subtlety (concrete methods can introduce type params, but interface methods cannot) to teach?

    I don't personally see this as a concern given that generic type parameters cannot be used today for either case. Those that need this new functionality will find it and understand the features and limitations and others will live without it as they do today. I do agree, though, that generic type parameters on interface methods will just become the next largest ask, but that was already covered earlier.

    Would this new functionality be released gradually, perhaps initially behind a GOEXPERIMENT flag? (I think it should.)

    I'm on the side of the fence that this functionality doesn't need a GOEXPERIMENT baking period, but I'm curious why you believe it does. Can you elaborate @jub0bs?

  10. kardianos commented on Jan 23, 2026

    @kardianos
    Contributor

    I appreciate that a generic method would not be used to satisfy an interface but would be treated (at least conceptually) as a namespaced generic function. This would meet a few of my needs pragmatically. Specifically, I make good use of SQL data table buffers and parameter fetching in some designs. I typically all something like row.Get("ColumnName").(int64) . But if the backing type is actually an int32 it will panic (at times the differences can be subtle) or I need an enum outcome, it adds more complications by first asserting to an int64 and casting to the enum type. I would much prefer row.Get[string]("ColumnName") or row.Get[enum.MyStatus]("TheStatus"). I have a helper function today that does the same, but it tends to be under used because then I have to bring in another package or remember to use it. I don't need generic methods to implement interfaces. But for data access, this will be extremely useful.

    Thank you.

  11. thwd commented on Jan 23, 2026

    @thwd

    Perhaps an extension could be considered (initially or later) to enable declaring specific concrete methods should exist and be available for interfaces.

    The already existing idiom:

    var _ io.Reader = (*Reader)(nil)

    Achieves the same. No need for additional syntax.

  12. dagood commented on Jan 23, 2026

    @dagood
    Contributor

    I have a sweet tooth when it comes to syntactic sugar, so I naturally like this proposal. 🙂

    I also liked the extension from @mpx at first glance. I thought it might be worth writing down the pattern that I think will start to show up without it:

    // Compare to:
    // func (*Reader) Read[E any]([]E) (int, error) { … }
    // func (*Reader) Read[byte]([]byte) (int, error)
    
    func (*Reader) ReadOf[E any]([]E) (int, error) { … }
    
    func (r *Reader) Read(p []byte) (int, error) {
        return r.ReadOf(p)
    }

    I think I can live with that. I do also find the argument from @Merovius against the extension convincing.

  13. jakebailey commented on Jan 23, 2026

    @jakebailey
    Contributor

    Achieves the same. No need for additional syntax.

    This is a cool trick I use often, but definitely not what I'd want to "declare" that a type should satisfy an interface through a specific instantiation.

  14. kylelemons commented on Jan 23, 2026

    @kylelemons
    Contributor

    To start off with, I am in support of generic methods, and I think this is likely the most practical way to get them.

    If I am understanding this proposal correctly, though, I suspect there will be an almost-immediate desire for cases like the a generic Read[T] method to be able to implement the io.Reader interface. While that would be a proposal we could entertain today, I think that would become a breaking language change after this proposal is implemented (and it might be difficult to resolve because we'd be bound by the current behavior of type asserting the now-legal values against the interface). Maybe we could allow it under the in modules requiring go 1.75 or later... approach, but it seems like it might be too subtle for that treatment. I suspect we are okay with precluding this future change, but think it's worth noting.

  15. 208 remaining items

  16. griesemer commented on May 26, 2026

    @griesemer
    ContributorAuthor

    This has been implemented and documented. The only thing left to do is removing the respective GOEXPERIMENT which we may do a bit later in the release process (it's useful to quickly eliminate generic methods as the cause for bugs).

  17. rudiservo commented on Jun 8, 2026

    @rudiservo

    I am going to leave my opinion and word of caution on why this might be a bad idea, now I have done my fair share of compiled but mainly scripting languages (php, javascript, bash, python), and the are 3 things that makes a project hard to maintain, bad programmers, abstraction programmers and new toy syndrome programmers.

    Bad programmers will use any resource the worst way possible just to get the job done without thinking about the consequences
    Abstraction will think they are so smart in making code that is abstract and beautiful, but only they understand how it works
    New toy syndrome programmers will find problems for the solution, so everywhere they can put it, they will.

    One example is javascript arrow function, now the arrow function is about the scope of variables that can be called in the function, but more than once I have been told is the new way to write functions and the old way (function) is not best practice anymore, it just gave way to even more abstract things like React, that I challenge anyone to try and make sense of it's inner-workings just by looking at the source code.

    The other example is php traits, while they are really simple and granted they are very interesting, it did put the OOP inheritance, polyformism, etc, a bit redundant, more recently they are also trying to mimic the JS arrow functions...

    Loads of other languages have these examples where something just made the language easier to make a mess inside projects and the abstraction adds a magical effect there the programmer no longer understands how the source code of a toll works without putting a significant amount of mental effort to solve relative simple issue.

    Go language is feature rich has it is, simple enough, no room for guessing around what calls what and where, although I recognize that stuff like SIMD is very interesting and probably very needed but that is adding capability not new ways to increase abstraction.

    Go is a tool used by humans, and human behavior while interesting also tends to make things a lot more complicated than it should be.

    Also I do not know how much this will slow down the compiler or add complexity to it, since one of the trademarks of go is fast and predictable compilation.

    So I am going to say this with the upmost respect, stop adding stuff to the language that will make room for a level of abstraction that will work against anyone using it, I don't think Go really needs it and I don't know of any project that was not made because Go didn't have generics or generic methods.

    Simple should not be easy and easy tends to complicate things.

  18. antichris commented on Jun 9, 2026

    @antichris

    @rudiservo That is not how the proposal process works, though. If you had any objections against this particular proposal, you had 5 months to join in the discussion and voice your concrete objections. That is, if you even have any concrete ones, not just general vibes.

    Please, in the future, you are very welcome to engage in the proposal process just like the rest of us gophers do: by expressing your endorsement, suggestions, concerns or objections on the proposals that are open for feedback, that have not yet been rejected or accepted. I trust you can engage in productive discussion of the current proposals. If you truly care about the language. And are not here just to parrot what trending social media personalities post about.

  19. spenserblack commented on Jun 9, 2026

    @spenserblack

    And are not here just to parrot what trending social media personalities post about.

    Just curious: are you referring to a specific incident, like a popular social media personality arguing against this proposal?

  20. AnatoleLucet commented on Jun 9, 2026

    @AnatoleLucet

    @spenserblack probably referring to this recent YouTube video from ThePrimeagen

  21. rudiservo commented on Jun 9, 2026

    @rudiservo

    @antichris Calling my experience in Software Engineering a parrot of social media is quite disrespectful, but I don't mind and I digress.

    I just got into Go a few months ago and I am enjoying the fact it does not have generics, everything is laid bare, I am exploring several packages, frameworks, sqlx, gorm, gin, fiber you name it, I am head first on learning the ecoystem, so I did not know this was going on, that is why I shared my opinion and a word of caution.

    Although I was brought aware of this by social media, if I agreed with such proposal I probably would not comment on it!
    I did not comment on the GC improvements that are very tangible and reasonable when it came out.

    But if we are going address opinions based on experience and concerns has "parroting of social media" then this is a non starter for me to comment on any other proposal.

    I'll summarize to I am not parroting, but you are judgmental of valid arguments and criticism without presenting any valid counter arguments, I would expect counter arguments rather than accusations.

    So what are your counter arguments?

    Just to put out an interesting pattern, very seldom languages remove things, because once it is in it, is really really hard to remove, once you put in generics, there is no going back without a huge amount of refactoring of highly complex abstraction.

    My point is that anyone adding features need to think about consequences, I don't think that no one with vast more experience than me have touched consequences about the subject that we often see in other languages, we see it has a fix for a problem we have that is not a big deal, but not the long term consequences of the abstraction.

    Go does not need to be javascript.

    And I also bring the point that the creator of Go (Ken Thompson) said on an interview, when questioned why he created Go, and the answer was C++ 0x propose standard.

    Less is more, simple is not easy.

    https://www.youtube.com/watch?v=c-P5R0aMylM

    I also would like to share one this piece by Loris Cro that I think is quite interesting.
    https://kristoff.it/blog/simple-not-just-easy/

  22. alexandradeas commented on Jun 9, 2026

    @alexandradeas

    Guys who don't pay attention to the proposals now annoyed that they don't pay attention to the proposals because they have opinions on things. I've been eagerly awaiting 1.27 for a while because I have legitimate uses for these which I'd like to implement.

    If you don't want to use generic receivers don't use them - no one is forcing you and there is no overhead to not using them - but don't try to act like you really care enough if you don't engage with the spec process.

  23. Rudde commented on Jun 9, 2026

    @Rudde

    I just got into Go a few months ago and I am enjoying the fact it does not have generics, everything is laid bare, I am exploring several packages, frameworks, sqlx, gorm, gin, fiber you name it, I am head first on learning the ecoystem, so I did not know this was going on, that is why I shared my opinion and a word of caution.

    What are you talking about? Go does have generics. And have had them for 4 years, since version 1.18

  24. rudiservo commented on Jun 9, 2026

    @rudiservo

    @Rudde I was taking about the Generics of this proposal, the generics of v1.18 the interface{} and any, althoug they solve a number of issues, they are also an easy way out for devs that are abstracting things that probably should not in the first place.
    addint the two, generic methods and generics, will cause more abstraction, thus more complexity.

  25. rudiservo commented on Jun 9, 2026

    @rudiservo

    @alexandradeas I am open for debate, I would expect counter arguments that would change point of view, yet none have been given, only accusations, if this is a prelude of what the go community is going to be is not a good one.

  26. dominikh commented on Jun 9, 2026

    @dominikh
    Member

    I am enjoying the fact it does not have generics

    Go has had generics for four years now. This change merely extends where generics can be used.

    My point is that anyone adding features need to think about consequences

    It took Go ten years to add generics, and another four years to expand where they can be used, both times accompanied by lengthy proposal processes with hundreds of comments arguing for and against generics. To suggest that the consequences haven't been thought about is absurd.

    I would expect counter arguments rather than accusations.

    There are over 250 comments in this issue alone, I'm sure arguments in favor of this proposal have been made. You haven't provided any new information other than your personal displeasure and general "we need to keep the language simple" arguments, which have already been made before.

    the generics of v1.18 the interface{} and any

    Those aren't generics.

    As others have pointed out, the proposal process has run its course and now is not the time to revisit basic arguments. Short of concrete, fatal flaws, we won't just remove generic methods again.

    If you want to continue arguing in vain, please take it to one of the community forums; the issue tracker is not the right place for that.

  27. locked as off topic and limited conversation to collaborators on Jun 9, 2026
  28. thepudds commented on Jun 9, 2026

    @thepudds
    Member

    Hi @rudiservo, as mentioned, this proposal has hundreds of comments, but the discussion here was also preceded by #49085 (362 comments, opened in 2021), #50981 (opened in 2022), and more discussion elsewhere, including during the many discussions of the original generics proposals.

    I think it's fair to say that the pros and cons of this proposal have been discussed extensively before it was eventually decided and implemented.

    Note we are also already in the Go 1.27 development freeze.

    FWIW, I recommend reading this section from the official Go proposal process at https://go.dev/s/proposal:

    Generally speaking, our approach to reconsidering previously decided proposals follows John Ousterhout's advice in his post “Open Decision-Making,” in particular the “Reconsideration” section.

    In short, as you can imagine for a project used by millions of gophers around the world, there needs to be an approach to avoid large amounts of time being spent needlessly re-discussing points that have already been discussed. In particular, the Go project generally does not reconsider prior proposal decisions unless there is significant new information as described in the John Ousterhout "Reconsideration" section.

    Having such a large ecosystem (and 9k+ open GitHub issues!) also means being thoughtful about what type of conversations happen in which places, and it is important to realize that not all conversations must or should happen on the Go issue tracker, which is not great at scaling discussions. Fortunately, there are many places gophers do gather, most of which have better features for more scalable discussions than a GitHub issue with hundreds of comments (which tends to lead to circular and repetitive discussions, among other problems).

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

    • Status
      Accepted

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions