Type parameters in method definitions

September 7, 2023

Yesterday we saw that when a method is defined on a generic type, the receiver must include type parameters. Now for all the relevant details:

Method declarations

… Syntactically, this type parameter declaration looks like an instantiation of the receiver base type: the type arguments must be identifiers denoting the type parameters being declared, one for each type parameter of the receiver base type. The type parameter names do not need to match their corresponding parameter names in the receiver base type definition, and all non-blank parameter names must be unique in the receiver parameter section and the method signature. The receiver type parameter constraints are implied by the receiver base type definition: corresponding type parameters have corresponding constraints.

type Pair[A, B any] struct {
	a A
	b B
}

func (p Pair[A, B]) Swap() Pair[B, A]  { … }  // receiver declares A, B
func (p Pair[First, _]) First() First  { … }  // receiver declares First, corresponds to A in Pair

I don’t think there’s a lot I can add to this. I think the most important thing to remember here is that the type parameter names in a method definition do not need to match those in the type definition. This is consistent with the naming of function parameters in type defintions versus function definitions, or interface definitions versus method definitions.

// Type definition vs. method definition
type Foo[A, B any] struct {
  a A
  b B
}

func (f Foo[NotA, NotB]) Bar[NotA, NotB] { ... }

// Function type definition vs function definition
type FooFunc (a, b int)

var fooFunc = func(notA, notB int) { ... }

// Interface definition vs method definition
type barInterface interface {
  Foo(a, b int)
}

var barImplementation struct {}

func (barImplementation) Foo(notA, notB int) { ... }

Quotes from The Go Programming Language Specification Version of August 2, 2023


Share this

Direct to your inbox, daily. I respect your privacy .

Unsure? Browse the archive .

Related Content


Method values

A quick reminder: In today’s live stream, I’ll be deploying a Go app to Kubernetes! I hope you’ll join me! Today we continue the explanation of Method values. There’s nothing too surprising today. The spec mostly just confirms what should seem natural… Method values … As in the discussion of method expressions above, consider a struct type T with two methods, Mv, whose receiver is of type T, and Mp, whose receiver is of type *T.


Method expressions, part 2

Today I’ll continue where I left off yesterday, talking about… Method expressions … Similarly, the expression (*T).Mp yields a function value representing Mp with signature func(tp *T, f float32) float32 The key difference to notice between this example and yesterday’s is that the first argument (that of the receiver) is a pointer here, but was not a pointer in the previous example: func(tv T, a int) int // First argument of type T, not a pointer func(tp *T, f float32) float32 // First argument of type *T, a pointer For a method with a value receiver, one can derive a function with an explicit pointer receiver, so


Method expressions

There was no livestream today, as I was a bit under the weather. I intend to be back live streaming next Monday as usual Method expressions If M is in the method set of type T, T.M is a function that is callable as a regular function with the same arguments as M prefixed by an additional argument that is the receiver of the method. MethodExpr = ReceiverType "." MethodName .