3 Things Go Needs Right Now More Than Generics

Don’t get me wrong — I like generics, and I’m excited to see what impact they will have on the Go language and its libraries. However, it is clear that agreeing on the specification and implementing generics has been a massive undertaking for the Go core team, at the unavoidable cost of other language developments.

I work daily with Go, and while the lack of generics can occasionally be a pain point, mostly it can be worked around with some combination of either abusing interface{} or manually generating the non-generic code. On the other hand, there are other pain points I feel much more often, and maybe other gophers do too…

1. Enums

These days it’s surprising to see a statically typed, modern, and production-ready language without any support for enums. For any readers not familiar with enums from other languages, put simply they are a way of declaring a custom type that may take one of a finite number of possible values. For example, you might want to declare a PrimaryColour enum with possible values RedYellow, or Blue.

In fact, you can think of all primitive types in Go as enums in disguise. Most obviously bool can be thought of as an enum that can only be true or false.

However, this also applies to other primitive types too. A byte can only represent the numbers 0–255 in the 8-bit range, an int32 can represent all possible signed integers in the 32-bit range, a pointer can represent all possible memory addresses in a (usually) 64-bit address space. So really, an enum is a tool to create your own primitive-like types.

Enums have real-world applications very often in programming — how many times do you use an API which requires you to specify one of a list of options?

For example, recently I was using an API that requires a SortOrder parameter to specify whether results should be sorted in ascending or descending order — this is a perfect use-case for a two-valued enum.

There are two common workarounds for the lack of a dedicated enum type in Go. The first is to define a type based on an integer and create some named constants using iota to represent the enum values:

type PrimaryColour int
const (
Red = iota
Yellow
Blue
)
func (c PrimaryColour) String() string {
switch c {
case Red:
return “Red”
case Yellow:
return “Yellow”
case Blue:
return “Blue”
default:
panic(fmt.Sprintf(“unknown colour %d”, int(c)))
}
}