home
navigate_next
Blog
navigate_next

How To Use Generics in Go 1.18

How To Use Generics in Go 1.18
Raj Negi
For the longest time, the biggest criticism for Go has been its lack of Generics. In fact it is the most requested feature.
How To Use Generics in Go 1.18

Introduction

For the longest time, the biggest criticism for Go has been its lack of Generics. In fact it is the most requested feature.

(From Go’s official survey

Let’s dive into what it means. What are generics? And why is everyone asking for it? And why did the maintainers of Golang say this is the biggest change to the language so far? Find out the answers to these questions along with a challenge at the end of this blog post.

The Need For Generics

For the longest time, the biggest criticism for Go has been its lack of Generics. In fact it is the most requested feature.

Consider an innocently small function that simply prints an int passed into it:

Now, imagine, if you were to implement this function for more data types. You’d have to do something like this, repeating the same functionality over and over:

This isn’t DRY. You’re repeating the same implementation over and over and it starts to become a huge code smell. Generics are here to solve this exact problem. It won’t make your code run faster, but it’ll keep your codebase clean and your developers happy!

Introducing Generics

Essentially, our old print() function gets replaced in the newer syntax like so:

Where T acts like a placeholder for any incoming parameter and infers the data type. We denote the possible datatypes our generic “T” can accept using square brackets right after the function’s name.

You can either call this function directly or provide the datatype explicitly:

A template for using generics in a function declaration:

Trouble In Paradise

Now, with your newly acquired knowledge about Generics, you’d be inclined to write a function that returns the smaller of the 2 values like so:

After all, it just makes sense! But in fact as soon as you build it, you run into an error. And it’s a compilation error:

./prog.go:32:5: invalid operation: a < b (type parameter T is not comparable with <)

The reason being, since T doesn’t have constraints on it (“any” is equivalent to interface{}), Go doesn’t know what to expect and hence can’t have operators being applied to it. To solve this, we can refer to this handy list of constraints that you can use https://pkg.go.dev/golang.org/x/exp/constraints

So, our new min function will look like this:

(Don’t forget to import the constraints package if your IDE doesn’t do it automatically.)

In fact, for whatever reason, if you want to constrain your min() function to only int32 and float32 datatypes, you can do that as well by using type sets:

A Small Test

Finally, a challenge for you, to see if you were paying attention! Do you think the following piece of code will compile?

If you said yes, you would be wrong, but don’t be disheartened. It’s because I haven’t told you how Golang infers the same underlying datatypes!

Here, we want minTypes to support all datatypes that have float32 as its underlying datatype. The way we accomplish that is by using the ~ sign. It in fact, immediately points it out at compile time:

./prog.go:15:17: myFloat does not implement minTypes (possibly missing ~ for float32 in constraint minTypes)

So, by simply adding a ~ in front of float32 in the interface declaration, we get rid of the compilation error.

And that is all! Now you’re ready to write non-smelly, DRYer code in Golang that will stand the test of time, lead to fewer bugs and ultimately keep you and your team happy!

Further Reading:

1. When To Use Generics - The Go Programming Language

For the longest time, the biggest criticism for Go has been its lack of Generics. In fact it is the most requested feature.
arrow_back
Back to blog