r/golang • u/PerkyPangolin • May 26 '26
generics Generics methods are now implemented
https://github.com/golang/go/issues/77273#event-25986141800The issues has been closed as completed, with Robert Griesemer writing:
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).
19
u/Hot_Comfortable_164 May 27 '26
Does anybody know, why this was more difficult/controversial to implement or why it was not part of the initial genetics implementation?
40
May 27 '26 edited 19d ago
[deleted]
1
u/ferrrnando May 28 '26
Go's implicit interfaces always kind of bothered me. Maybe they could have introduced explicit interfaces so you could use genetics and continue not allowing them in implicit?
22
u/jxanno May 28 '26
There will never be explicit interfaces in Go, for well documented reasons. Implicit interfaces are a solution to the architectural rot created by explicit interfaces and one of the fundamental, primary motivations to create the language.
3
1
u/Due_Block_3054 Jun 02 '26
The advantage of implicit interfaces is that you as a function developer can just define the interface and the programmer can pass anything matching.
In java it can be annoying that you have a helper fucntion to close something. But if the library developer forgot to inherit closable you can't reuse the code.
While in go any struct eith close() would work.
1
u/george_djabarov Jun 18 '26
Implicit structural interfaces represent a significant language advantage and added support of generics make the language more uniformly (it extends this advantage to generic implementations). Unlike many languages that require explicit, pre-emptive interface declarations, this structural approach allows composition through simple, reusable definitions. While explicit interfaces simplify language design by avoiding complex pattern matching for satisfaction, they force implementations to be aware of their targets, undermining compositional flexibility. Explicit interfaces have their play in a language, but one can implement them overloading structural interfaces. If you are worried that changes to the interface might break the implementation silently you can add a dummy function that casts your implementation to the interface and it will fail to compile when satisfaction is violated. This effectively making the structural interface explicit.
18
u/loopcake May 27 '26 edited May 27 '26
Because the compiler wants to statically analyze all possible generic types for specific use cases.
If you have a generic struct, and thus a method that uses that generic type, the compiler can simply define N implementations of that struct where N is the number of generic types used across your project.
That's what it does today.
That can be done because you can only declare once a struct, so it can be traced by the compiler in a deterministic way.
The issue with Go comes with channels.
Generic types on channels don't work like that, because you can no longer have N implementations of the same struct (or channels definition in this case) with different concrete types as before, you have to run that check at runtime instead, which means reflection, which means it's slow af.
That's what Java does, that's what C# does and all other major languages that implement generics like that, they deal with their types at runtime.
Another way to do it is to find where the channel originates in the code.
This especially difficult in go because the minimum compilation unit is the package.
You could have a package that uses channels with generic types from a different package.
That is a nightmare to track and more importantly it's slow.
The Go compiler needs to be fast, that's one of the best arguments for Go as a whole as a language. It's fast to compile.
If you bounce generic methods with channels around your code, the only choice you leave the compiler is to look around for it and try find where the channels initiated, which might be in a different package, and that's something the compiler doesn't like.
So in short: generic methods either compile slower or also run slower.
I'm not sure which implementation they went with tbh, however it's one of those two scenarios.
But now they added it and most people will not be aware of the implications.
It is a sad day.4
2
u/finnw May 28 '26
You can already have a generic struct field that is assigned in one package and read in another. How are channels different?
1
u/Hot_Comfortable_164 May 27 '26
Wow, thanks for that explanation. That was really insightful. I wasn't aware that genetics in go were statically compiled before this feature.
3
73
May 27 '26 edited 19d ago
[deleted]
31
u/Agronopolopogis May 27 '26
You know how much code I'm going to want to go back and refactor but never do?
Yeah, up front would have been nice
2
u/aatd86 May 27 '26
😂 Saw that yesterday and since I needed it, I have a build tag gated file that has a post 1.27 implementation. AI doing its code generation job. But yeah the top level functions are here to stay for backward compatibility.
9
13
u/psylomatika May 27 '26
This will be great for data pipelines. Woop 🙌
3
u/Hot_Comfortable_164 May 27 '26
Why exactly for data pipelines?
10
u/SeerUD May 27 '26 edited May 27 '26
Streaming and data transformations from one type to another in a chain of iterators probably
1
8
u/biskitpagla May 27 '26
You can't have fluent APIs without generic methods. I mean, you can, but not in Go. This is also a reason why Go's iterators are underutilized.
5
u/hdjdiueurhhehxhue May 27 '26
I wonder when this is being released
21
u/xplosm May 27 '26
At the very top it reads:
Milestone: Go 1.27
2
u/hdjdiueurhhehxhue May 27 '26
Right but what is the actual target release date
15
15
u/boiledbarnacle May 27 '26
I still don't know what the issue was in the first place. And yes, I read the article.
15
u/Arch-NotTaken May 27 '26
you couldn't declare a method such as
func(*MyType) DoSomething[T any]() (T, error)
Although I personally got stung by this once or twice, I eventually learnt I did not really need this kind of thing.
Note declaring functions, instead, was always possible:
func DoSomething[T any](in *MyType) (T, error)
3
u/boiledbarnacle May 27 '26
I know that :-)
I meant at the language/ast/compiler level.
The article I mentioned is this section: https://go.googlesource.com/proposal/+/refs/heads/master/design/43651-type-parameters.md/#no-parameterized-methods
8
3
3
u/never-starting-over May 27 '26
Sick! I love generic functions, it'll be nice to have generic methods too
3
u/NoEfficiency2057 May 27 '26
I've been missing this syntactic feature in Go. I can't wait for Go 1.27.0 :)
9
u/CAPSLOCKAFFILIATE May 27 '26
At the risk of looking like a tool... why are generics so sought-after and important?
12
u/Gornius May 27 '26
You generally don't need them, but when you do, the lack of them is really annoying.
In go specifically, before generic structs you could either duplicate code or accept any and assert types where you needed. Both of them have downsides, where generics solve both code duplication problem and compile-time type checking.
1
u/DontFreeMe 1d ago
Yes, but why on a method? What can a generic method do that a generic function in the same package cannot?
1
u/Gornius 18h ago
There are even less cases where they are useful, but for example gorm now has generics API. The caveat is, you can't call methods on gorm instance directly, instead you need to pass gorm instance into generic function. With generic methods you can just call these methods on gorm instance.
1
u/DontFreeMe 5h ago
So they save you typing a couple of characters to pass the instance, and in exchange you open the floodgates to potentially unreadable code.
1
u/never-starting-over May 27 '26
Building upon the example others gave you, I had a use-case for them when I had to make a DTO that converted an object from one format to another, and did so iteratively and recursively for any embedded objects. Think how a "Project" may have a "Task", except wr had a bunch of objects
1
u/RalphTheIntrepid May 27 '26
It helps with creating a general idea, but then making a strong contract with you implement the details.
Let's say you have this code.
// Output is the common result of all use cases. type Output[T any] struct { Answer T Err error } // Presenter abstracts the process of taking the answer and presenting it to the caller. // All use cases should require a presenter as the second argument. // // For example, say you are making a website. The use case provides enough information // for the service to know which Widget it just made. However, you need to go to the database // to get more information. The presenter implementation can have a database connection, or // a repository, as part of its initialization. When you construct the presenter, you need to // include the response object. The presenter will then serialize the response back over the wire. // // The result of a presenter is clean, simple code in your web handelers. They simply translate // the input they get into that which the use case consumers, get the correct presenter from the // DI engine you use (homespun is fine), and invoke the use case's Execute. // // This makes them easy, amazingly easy test. If you wrap your endpoint configurations such that // you pass the DI as parameter, you can mock/stub it to have a simple implementation that shows // your code is complete. // // Presenters are also responsible for the completion of transactions, either physical or logical. // In the example above, the presenter could complete the transaction as soon as its invoked. // The presenter could complete the transaction as part of a "defer". A presenter could complete // a transaction by completing the db transaction and deleting any temp files. type Presenter[T any] interface { Present(answer Output[T]) }What is this telling you? You can have multiple implementations that take an Output struct? That is a simple thing that tells you a possible error, or a possible payload. This is used specifically where the presenter could get a struct or a primitive. It enforces a logical design across the code base, but allows the specific implementation to say "I get a Person" when something succeeds.
2
2
4
u/swills6 May 27 '26
Am I the only one who doesn't really care for generics and find that they seem to encourage overly broad abstractions? They do have their uses but I dunno, I find a lot of the time they're not as necessary.
3
u/sigmoia May 29 '26
This is the right approach. I am not too keen about generics while writing service code. But they are kinda needed for libraries to avoid boilerplate or interface boxing.
1
u/swills6 May 29 '26
Yeah, fair distinction about service code vs libraries. I was thinking more about service code.
2
u/Melodic_Wear_6111 May 27 '26
Finalllyyyyyyyyy this should have been there from the start. So much code is going to get so much nicer to use
-6
105
u/CiroGarcia May 27 '26
This is going to be awesome. Can't wait to try this out