Recently, the Go team announced an updated draft design for their Generics in Go proposal. It goes into a lot of details about why certain decisions were made, implementation details, etc.
In this article, my goal is to summarise the major upcoming changes, as the whole draft design can be a mouthful for many.
I will provide some code snippets to demonstrate the major features as well as give you the chance to experiment yourself with them, thanks to the new Go playground with support for generics.
Type Constraints in Generic Functions
Here's how a generic function looks like without any constraints on the type parameter:
To add constraints on the generic type, you can demand that it implements a given interface:
To specify multiple type parameters, separate them by commas:
Constraints on multiple type parameters are written the same way you write function argument types:
And here's how to specify different types for both parameters:
Type Lists & comparable
Instead of constraining types based on a set of methods, you can constraint them based on a set of supported types. For example, you could specify that you accept a generic type which can only be an int or a long.
This allows you to e.g. leverage operators like "less than", "greater than", which are only available for basic types in Go:
You also have an out-of-the-box constraint called comparable, which constraints types to those which support the == and != operators.
Interfaces using these constraints - type lists and/or comparable, cannot be implemented by a struct.
They can only be used for type constraint definitions.
Structs can be defined using a generic type. Once specified, in the type declaration, there is no need to specify the type for all the functions of the type:
You can also do that in interfaces. This is especially useful when a type constraint depends on itself.
E.g. you have a type constraint for T, which requires an Equal method, which accepts a T parameter:
In case you need to specify a type parameter, who has a state-modifying function (e.g. a setter), then you can specify a pointer type constraint:
Notice how this example above requires that you explicitly specify the type you'll use in the function - FromStrings(Settable)...
This is because whenever the type is not present as a function argument, the compiler cannot infer the actual type once the code is compiled. Hence, you need to explicitly specify it.
This article was purposefully succinct and straightforward. Hopefully, it will help you quickly get up-to-date on the latest generics draft design, while you're drinking your morning coffee.
However, there is a lot of rationale behind any single design choice around generics in Go. If you are interested to dive deeper into this subject, check out the official draft design doc.
So, do you like the latest Go Generics draft design?
Let me know in the comments section below.