Go Generic Programming - Testing the waters
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”.