5/28/2026 at 1:13:12 AM
> 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.I don't really understand this argument. I read the discussion linked to[1], and yeah, monomorphization approaches (whether at compile time, link time, or runtime with JIT) are obviously going to be difficult or impossible, but the reason against using runtime reflection is mostly that it's slow. But that runtime reflection is exactly how you would work around it today.
For the Identity example, could the interface be compiled to be basically equivalent to:
Identity(any) any
and then at the callsite add a cast of the return type to T?
I suppose primative non-pointer types add a bit of a wrinkle but even if it generic methods was restricted to pointer types, that's better than nothing. And the number of those types is relatively small, so when the implementation is compiled it could just instantiate method implementations for all the primative types, if they apply, and then maybe remove them if they aren't needed at link time.
Of course it's also possible there is some detail I've missed.
[1]: https://go.googlesource.com/proposal/+/refs/heads/master/des...
by thayne
5/28/2026 at 5:51:51 AM
> but the reason against using runtime reflection is mostly that it's slow.More specifically, it is that it would introduce surprising performance cliffs – code becoming surprisingly slow due to seemingly unrelated changes.
Though BTQH I think an even more important argument is that you would need to have effectively two generics implementations, one working at runtime and one working at compile time. That's a lot of complexity, with surprising failure modes if these two are not bug-compatible.
> But that runtime reflection is exactly how you would work around it today.
I think the overwhelming majority of people will "work around it" by just not trying to use generic methods.
by Merovius
5/28/2026 at 7:54:03 AM
> you would need to have effectively two generics implementations, one working at runtime and one working at compile timeMy understanding is that go already has a hybrid system works at compiletime and sometimes at runtime.
by thayne
5/28/2026 at 9:50:39 AM
I'm not sure what you mean. Perhaps you are referring to the reflect package? In that case, yes, that exists. But it is limited in its power (for example, it doesn't allow to create types with methods – precisely because of the difficulties we are talking about) and a comparatively frequent source of bugs. If anything, it provides pretty strong evidence for the problems with this approach.by Merovius
5/28/2026 at 4:26:55 PM
https://go.dev/doc/faq#generics_implementationMy point is for interface generics it could just always use a single instantiation. Similar to what java does.
Or alternatively, go could go the other direction and add a new type of interface that is only for use in generic constraints, and then generic methods could be part of that interface, but not normal interfaces, so that the generic methods could be called from other generic functions. That would be similar to rust and c++.
by thayne
5/28/2026 at 10:30:35 PM
When I said "you need a runtime implementation of generics" I did not mean "you need dynamic dispatch". I meant "you need a type-checker and at least limited code generator at runtime".> Similar to what java does.
Yes, if you completely forego the static implementation, you can deal with just one. Then all code is slow.
Java can get away with it, because it has a JIT compiler – so it isn't subject to the same "no runtime code generation" design restriction Go is. That also means, it can run on fewer platforms than Go.
> add a new type of interface that is only for use in generic constraints
Yes, that would be feasible. It has been ruled out, because we really don't want to have interfaces that can not be used as types. They currently exist, but the goal is to remove that restriction, not to add more of the same.
I'll note that either way, at that point we are firmly outside the realm of this particular thread. It's no longer what I was responding to.
by Merovius
5/28/2026 at 7:18:07 PM
Sorta, but it's important for the calling convention that the compiler is consistent on what is done at compiletime vs runtime. Because methods are "normal functions" for the calling convention (and can be assigned to function-typed variables), there would be a lot of gymnastics required for the compiler to make runtime-generated variants of methods work.by HALtheWise
5/28/2026 at 1:55:40 PM
BTQH?by Boxxed
5/28/2026 at 2:20:21 PM
Maybe a typo for To Be Quite Honest?by Falell
5/28/2026 at 3:31:30 AM
> Of course it's also possible there is some detail I've missed.Can't speak too deeply for Go specifically, but I do know on .NET one of the big reasons generic methods where T is a structure gets monomorphized per type, is so that stack size is adjusted and potentially even arg passing (i.e. large struct) as far as the caller/callee.
by whaleofatw2022
5/28/2026 at 6:05:46 AM
Like Java‘s generic erasure? Primitive types aren’t supported at all, have to used boxed ones. Its slightly annoying but not too much. You can fall back to arrays to have performant primitive containers.by MrBuddyCasino
5/28/2026 at 2:01:34 PM
The real problem is that Go produces interface implementations dynamically.The determination wether type T implements interface I is made at runtime. So is generation of the necessary vtables to produce the interface implementation.
So you can do things like this in package a:
type S struct {
//...
}
func (s \* S) Foo() {
//..
}
and something like this in package b: type Foo interface {
Foo()
}
func DoSomethingWithAFoo(f Foo) {
}
and something like this in package c: func Stuff(obj any) {
theFoo, _ := obj.(b.Foo)
theFoo.Foo()
}
And then do: var s a.S
c.Stuff(s)
And everything works.For generic functions, go uses a strategy similar to C++ templates: when you call a generic function the compiler statically produces a concrete specialization of the generic function based on the inferred types for generic parameters.
That is, if you do:
func Bar[T any](x T) {
//...
}
And you do: var x int
var y string
var z float64
Bar(x)
Bar(y)
Bar(z)
The compiler statically generates 3 versions of Bar, one that takes an int, one that takes a string, and another that takes a float64.These two things don't work well together. If I have a variable typed as `any`, and I want to cast that to an interface, I need to dynamically determine 2 things:
1. The shape of the interface's vtable. The go runtime does this by iterating over the runtime metadata for the interface type.
2. For each named method in the interface's vtable, the address of the concrete function to stick in that vtable slot. This is done by accessing the reflection metadata for the implementing type. It verfies the method with name X for type T matches the required signature for the method with name X for interface I, then sticks that method pointer into the appropriate vtable slot.
The problem, however, is what happens when the method with name X is generic. There may, or may not, be an actual concrete method for the set of type parameters. It's possible that statically type T does implement interface I (via generic methods) but that dynamically it doesn't because the particular generic instantiation needed for the particular interface was never made statically.
Prior to go 1.27, this was never an issue, because methods could not declare their own type parameters. They could reference the generic parameters of the receiver, but once the receiver type was known, there was only ever one concrete method X for that receiver.
Once you allow methods to have their own generic type parameters, the compiler can introduced several different concrete implementations for a method X.
This is ok, when you do somethnig like:
var x SomethingWithGenericMethods
x.Foo(1)
x.Foo("hello")
x.Foo(1.2)
Because the compiler knows statically from the Foo call sites which concrete methods it needs to generate.But, when you introduce a dynamic cast:
var x SomethingWithGenericMethods
var i SomeInterface
i = x.(any).(SomeInterface)
i.Foo(1)
i.Foo("Hello")
i.Foo(1.2)
It's entirely possible that the necessary Foo implementations don't actually exist in the binary.So, go 1.27 introduces generic methods, but it gets around this problem by saying:
1. Interface types can't define generic methods
2. Generic methods can't be used to implement interfaces
Thus, it allows adding generic methods without introducing the issues that crop up with dynamic interface implementations.
by swisniewski