Go Type Parameters Proposal is expected to be implemented with Go 1.18 early 2022.

The Very high level overview section contains a nice overview of what to expect.

If you have seen generics in other languages perhaps the most curious differences (other than using square brackets), are union types:

type SignedIntegers interface {
	int | int8 | int16 | int32 | int64
}

Similar in syntax to scala3/dotty union types, although in Go is only allowed in constraints. The type set of this union element is the set {int, int8, int16, int32, int64}.

Another interesting difference is the Approximation Constraint, written as ~T. The type set of ~T is the set of all types whose underlying type is T.

Testing the waters

A map function can be written as:

package main

import (
	"fmt"
)

func mapFunc[A any, B any, F func(A) B, S ~[]A](f F, a S) []B {
	if a == nil {
		return nil
	}

	res := make([]B, 0, len(a))
	for _, e := range a {
		res = append(res, f(e))
	}

	return res
}

func main() {
	type User struct {
		ID   int
		Name string
	}

	usernames := mapFunc(func(u User) string { return u.Name },
		[]User{
			{
				ID:   1,
				Name: "Foo",
			},
			{
				ID:   2,
				Name: "Bar",
			},
		})
	fmt.Println(usernames)
}

Go can infer types, allowing us to omit them, which helps readability.

Collections

So far few new packages have been added around generics:

Seems like authors are cautious around what to add. One would expect to see the usual suspects map, filter and reduce and a collections package, perhaps something the community will fill in.

Final Thoughts

Generics is going to remove a lot of code duplication at the cost of increased cognitive load parsing function signatures.

I am curious to see:

  • If some patterns will emerge around naming types

  • How to define constraints, eg for F:

    • func mapFunc[A any, B any, F func(A) B, S ~[]A](f F, a S) []B
    • func mapFunc[A any, B any, S ~[]A](f func(A) B, a S) []B

Perhaps something go fmt could “fix”.