Geek Culture
Published in

Geek Culture

Generics in Go

The Go team has released a draft design for type parameters, which are colloquially referred to as generics. It’s expected to be included in Go 1.18. While there might still be last-minute changes.

Go is a statically typed language, which means that the types of variables and parameters are checked when the code is compiled. Built-in types (maps, slices, channels) and functions (such as len, cap, or make) can accept and return values of different types, but user-defined Go types and functions cannot. If you are familiar with Java, C++, or another language with some variety of generics, the simplicity of Go’s type system has probably caused a few frustrations.

If you are familiar with dynamically typed languages, where types are not evaluated until the code runs, you might not understand what the fuss is about generics, and you might be a bit unclear on what they are. It helps if you think of them as “type parameters.” We are used to writing functions that take in parameters whose values are specified when the function is called. Similarly, we create structs where the value for the fields is specified when the struct is instantiated. Generics is the concept that it is sometimes useful to write functions or structs where the specific type of a parameter or field is specified when it is used.

Since the first announcement of Go, there have been calls for generics to be added to the language. Russ Cox, the development lead for Go, wrote a blog post in 2009 to explain why generics weren’t initially included. Go emphasizes a fast compiler, readable code, and good execution time, and none of the generics implementations that they were aware of would allow them to include all three. After a decade of studying the problem, the Go team thinks it has a workable approach outlined in the Type Parameters-Draft Design.

We’ll see how generics work in Go by looking at a simple stack. If you were to implement a stack for any type without generics, here’s what you’d do:

We can use it like this:

This works and prints out 30 true, but you can insert a value of any type into this stack, and if you want to do more than print out the value returned by Pop, you need to use a type assertion to convert it to the type that was inserted. Let’s see how Go generics make this stack type-safe:

There are a few things to note. First, we have [T any] after the type declaration. Type parameters are placed within brackets. They are written just like variable parameters, with the type name first and the type bound second. You can pick any name for the type parameter, but it is customary to use capital letters for them. Go uses interfaces to specify which types can be used. If any type is usable, this is specified with the new universe block identifier any, which is exactly equivalent to interface{}, but is only valid within a type constraint. Inside the Stack declaration, we declare vals to be of type []T instead of []interface{}.
Next, we look at our method declarations. Just like we replaced interface{} with T in our vars declaration, we do the same here. We also refer to the type in the receiver section with Stack[T] instead of Stack.
Finally, generics make zero value handling a little interesting. In Pop, we can’t just return nil, because that’s not a valid value for a value type, like int. The easiest way to get a zero value for a generic is to simply declare a variable with var and return it, since by definition, var always initializes its variable to the zero value if no other value is assigned.

Using a generic type is very similar to using a nongeneric one:

The only difference is that when we declare our variable, we include the type that we want to use with our Stack, in this case int. Now, v has a type int and not interface{}, so you can use it without a type assertion. Furthermore, if you try to push a string onto our stack, the compiler will catch it. Adding the line:

produces the compiler error:
cannot convert “nope” (untyped string constant) to int

Since generics are not officially released yet, they are not supported on The Go Playground. However, there’s a temporary “Go2Go” Playground where you can try out the generic stack.
Let’s add another method to our stack to tell us if the stack contains a value:

Unfortunately, this does not compile. It gives the error:
cannot compare v == val (operator == not defined for T)

Just as interface{} doesn’t say anything, neither does any. We can only store values of any type and retrieve them. To use ==, we need a different type. Since nearly all Go types can be compared with == and !=, a new built-in interface called comparable is defined in the universe block. If we change our definition of Stack to use comparable:

we can then use our new method:

This prints out:

You can try out this updated stack.

In the resource of this post, you can learn more about Go Generic with different titles, For instance: Use Type Lists to Specify Operators, Generic Functions Abstract Algorithms, Type Lists Limit Constants and Implementations

Conclusion

Adding generics clearly changes some of the advice for how to use Go idiomatically. The use of float64 to represent any numeric type will end. We will no longer use interface{} to represent any possible value in a data structure or function parameter. You can handle different slice types with a single function. But don’t feel the need to switch all of your code over to using type parameters immediately. Your old code will still work as new design patterns are invented and refined.

Since there are no production implementations of generics, it’s hard to say how they will affect performance. It’s likely that there will be some impact at both compile-time and runtime. As always, the goal is to write maintainable programs that are fast enough to meet your needs.

We took a look forward at generics and how they will change how we use Go to solve problems. The implementation isn’t released yet, so there’s still a possibility of additional changes, but they are likely to be minimal.

--

--

--

A new tech publication by Start it up (https://medium.com/swlh).

Recommended from Medium

How You Can Prevent Committing Secrets and Credentials Into Git Repositories

Building a Mobile App in 10 Days with React Native

The “proper” way of documenting products

Typescript and the Three Perspectives of Software Development

Sink or Swim: Do’s and Don’ts of Git Branching Strategy

AWS Lambda integration with Snowflake

Why Aren’t We Writing Unit Tests?

Advice from the Trenches: Working with your Dev Team

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store
Ahmad Berahman

Ahmad Berahman

I have a dream to have a spectacular garden

More from Medium

Golang with Leetcode: Remove Nth Node From End of List

Go Programming | Array vs. Slice

Implementing a Basic HTTP Server Using Go

Protocol buffers vs JSON | An interview anecdote