Unlock seamless workflows and faster delivery with our latest releases – get the details

Why your team is stoked about generics in Go

Explaining why people are stoked about generics in Go to people who don't know Go.

Published

  • Knut Melvær

    Knut Melvær

    Head of Developer Community and Education

I have barely at a “hello world” level in Go, but I have seen talk about “generics” in the Sanity slack for years. Recently generics were merged into the main branch to much jollification amongst our backend and full-stack developers. As a devrel, I’m professionally inclined to be curious whenever developers express enthusiasm about anything, so I asked: What’s the deal with generics? Why are we stoked?

So, assuming that you know a bit of programming, but not necessarily Go, let’s take a small step back: Go is a statically typed language developed at Google aiming to be awesome for networked applications. Which it is, and used a lot internally to build and run our global real-time content platform that processes over 4 billion requests every month.</pitch>

Statically typed means that when you write Go, you also declare the data types of the variables and functions you’re writing. If you’re familiar with JavaScript, that’s a dynamic language where you’re not doing that (which makes TypeScript a thing). So a function that returns “hello world” if you give it the string “world”, looks like this:

func hello(string thing) string {
  return fmt.Println("hello " + thing)
}

This basically tells you that what you put into the function should be a string, and what you get out is also a string.

Now, Go also lets you declare more complex data types through something called interfaces, which does the same thing. The example one of my colleagues gave me was the following:

Let’s say you want to make a “cache” in Go, you might define the interface like this:

type Cache interface {
  Get(key string) interface{}
}

So applied to a function, we’ll say that you can input a string for the key, and get back “any type”, which is the `interface()` part. The annoying thing is that then you have to cast whatever is returned to the data type you want.

cache.Get("foo").(string)

Or else you need to write multiple functions with the same logic, but with different data types specified. So code repetition that feels unnecessary and unwieldy.

With generics you can start writing interfaces like this:

type Cache[T any] interface {
  Get(key string) T
}

Which guarantees that your function always will return the agreed-upon type. What has really happened here is that Go does the heavy lifting of implementing the function for each type instead of you having to do it. This might not have been easy to make, but it’s one of the advantages of having a statically typed and compiled language.

Now, support for generics in Go isn’t uncontroversial. Of course, you’ll find discussions about on Hacker News and the like being concerned that this pattern introduces more complexity. Then again, for our backend team, it represented better developer experience and lines of code we can delete from the codebase. And that is always a good thing!