Why can a Go interface never declare a method that has its own type parameter?
answer
- one table entry per interface method
- who chooses the type: caller or implementation
- how many instantiations exist, and when
- what result type would the interface even state
- a constraint is just an interface too
basics
~20 sAn interface value dispatches through a table holding one function pointer per method, filled in when a concrete type is assigned. A method whose type argument is picked at the call site has an unbounded family of instantiations, so there is no single entry to store. Interfaces therefore forbid it.
solid answer
~50 sInterface dispatch in Go is a lookup: an interface value pairs a concrete type with a table that has exactly one entry per interface method, and calling through it jumps to that entry. A method that declares its own type parameter, like `Decode[F any](frame []byte) (F, error)`, has no single implementation — the compiler generates code per type argument shape, and the set of call sites is open-ended, including in packages compiled later. There is nothing to put in the table, and the signature is not even fixed, since the result type varies with `F`. So an interface method may not declare type parameters, and, from the other side, a generic method cannot implement an interface method even when the names line up. Because constraints are interfaces, a constraint cannot demand a parametric method either. The escape hatch is a package-level generic function.
code
go · 10 lines// Not valid Go: an interface method may not declare type parameters.
type BadDecoder interface {
Decode[F any](frame []byte) (F, error)
}
// Valid: the parameter sits on the interface type, so each instantiation
// has one fixed method signature to dispatch on.
type Decoder[F any] interface {
Decode(frame []byte) (F, error)
}go deeper
Remember the two halves of the rule: an interface method cannot declare type parameters, and a method that declares them cannot implement an interface method. Being able to state both is enough at this level.
Explain the mechanism: an interface value carries one table entry per method, resolved at assignment, while a parametric method has an open-ended set of instantiations and no fixed result type. Mention that constraints are interfaces and inherit the restriction.
Show you know the way out: move the parameter onto the interface type, or onto a package-level function. Be able to say which of those a caller can live with, given they commit to the type argument at different moments.
Own the framing that interfaces abstract over the implementation and type parameters abstract over the caller, so a single method cannot do both. That framing decides where the seams in a package go long before any code is written.
## The rule Two restrictions travel together, and they are both about the same thing: 1. An **interface type may not declare a method with its own type parameters**. `Decode[F any](frame []byte) (F, error)` inside an `interface { ... }` block is not valid Go, in any version, including Go 1.27 which introduced generic methods on concrete types. 2. A **generic method cannot implement an interface method**. If `Adapter.Decode` declares its own `F`, then `Adapter` does not satisfy an interface requiring a `Decode` method — the parametric method simply does not count. A type with a generic method is not shut out of interfaces entirely; its *other*, ordinary methods still satisfy whatever they satisfy. It is that one method that cannot participate. ## Why: what an interface value actually is At run time an interface value is a pair: a pointer to the dynamic value and a pointer to a table describing its concrete type. That table contains one entry per method the interface requires, resolved when the concrete type is assigned into the interface. A call through an interface is an indirect jump to a fixed slot in that table. Now consider what a parametric method would need. `Decode[F any]` is not one function. The compiler produces code per type argument — sharing an implementation across type arguments with the same memory shape and passing a dictionary of type information — so `Decode[Heartbeat]` and `Decode[Payload]` do not resolve to the same entry point in general, and neither do the instantiations that some *other* package, compiled later, will ask for. There is no finite list of entries to build. The table cannot be constructed at the moment of assignment because the set of instantiations is not known then, and it is not known ever. ## Why: the signature does not exist There is a second, more basic problem, and you can see it without knowing anything about dispatch tables. An interface method has a *signature*: a fixed list of parameter and result types. What is the result type of `Decode[F any](frame []byte) (F, error)`? It depends on `F`, which the caller supplies. Nothing about the interface can state "returns whatever the caller asked for" — that is precisely the information an interface deliberately erases. Interfaces abstract over the concrete type on the *receiver* side. A method type parameter abstracts on the *caller* side. The two do not compose. This is why interfaces and generics in Go are described as complementary rather than alternative: subtype abstraction hides the implementation from the caller, parametric abstraction hides the caller's type from the implementation, and one method cannot do both. ## Constraints inherit the restriction A generic constraint is written as an interface, so everything above applies to constraints too. You cannot write a constraint saying "any type that has a `Decode` method with its own type parameter". A constraint can require an ordinary method, and it can require a type set, but it cannot demand parametricity from its members. This matters when you sketch an API and reach for "I will just require a generic method on the constraint". You cannot; the operation has to become a package-level generic function that takes the value as an argument, and the constraint then requires whatever ordinary methods that function needs. ## What this looks like in practice Suppose you write an adapter that turns another team's wire frames into your own structs, and you want callers to name the target type at each call. The natural instinct is: ```go type Decoder interface { Decode[F any](frame []byte) (F, error) // not valid Go } ``` The compiler rejects the interface itself. The alternatives, in rough order of preference: - **A package-level generic function.** `func DecodeFrame[F any](a Adapter, frame []byte) (F, error)`. Callers name `F`, or let inference find it from an argument. Nothing is hidden behind an interface, which is usually fine. - **A generic type instead of a generic method.** `type Decoder[F any] interface { Decode(frame []byte) (F, error) }` is perfectly legal: the parameter is on the interface *type*, so once instantiated as `Decoder[Heartbeat]` the method signature is fixed and dispatch works normally. The cost is that the caller commits to `F` when it obtains the interface value, not at each call. - **A concrete signature.** Have the method return a defined struct, or `any`, or write into a caller-supplied pointer: `Decode(frame []byte, into any) error`. This is what `encoding/json` does with `json.Unmarshal`, and it trades compile-time typing for a run-time reflection step. The second option is the one people miss. "Interfaces cannot have generic methods" does not mean "interfaces and generics do not mix" — a parameterised *interface type* is ordinary and useful. It is only the per-call, per-method parameter that dispatch cannot carry.
- Does a type with one generic method lose the ability to satisfy any interface?No. Its ordinary methods still count toward every interface as usual; only the parametric method is excluded from satisfying an interface method. A type can have a generic helper method and still be assignable to an interface built from its other methods. The trap is a one-method interface whose single method is the one you parameterised.
- Can an interface type itself be generic in Go?Yes, and this is legal and common. Writing `type Decoder[F any] interface { Decode([]byte) (F, error) }` puts the parameter on the interface type; once instantiated as `Decoder[Heartbeat]`, the method has a fixed signature and dispatch is ordinary. The difference is when the caller commits to F: at the point it obtains the interface value, not at each call.
- Can a generic constraint require that its type argument has a generic method?No. A constraint is written as an interface, so it inherits the same restriction: it may require ordinary methods and a type set, never a method with its own type parameters. If your design needs that capability, express it as a package-level generic function that takes the value, and have the constraint require only the ordinary methods that function calls.
saying these in an interview costs you the question
- Says Go 1.27 allowed generic methods on interfaces too
- Claims Go erases type arguments at run time
- Confuses a generic interface type with a generic interface method
- Thinks a pointer receiver would make it satisfy the interface
- Believes a constraint may require a parameterised method