Juan Álvarez

@shixzie

Generics on Go’s stdlib

So recently Russ Cox gave a talk at Gophercon about The Future of Go”, and he mentions that in order to get X feature in Go, we must first show enough examples of why Y its a problem, so it gets attention from the Go team, helping them understand our (the community’s) point of view, we need to convince them that Y is a real problem and that X is probably the best possible solution.

So . . . now what??

To accomplish that, we need to create the so called Experience Reports, basically posts about the described above. So here we are.

Also, I would like to point out that this post does NOT cover any concrete implementation examples but rather give a brief look at what some pkgs of the stdlib may look like if something like generics were implemented.

The Problem

I like to describe the problem as:

The lack of generics / way of declaring dynamic behavior while keeping type safety, forces the users to grow their code base by either:

  • The use of code generation tools that just makes the code way more unreadable for the end-user and creates confusion due to various functions with similar names instead of having just one. — Sacrifice code readability and API complexity for type safety —
  • The use of interface{} (empty interfaces) to avoid numerous functions with similar names but at the cost of type casting/assertion almost everywhere. — Sacrifice type safety for readability and reduced user API —

In either case we’re making use of code that doesn’t actually belongs to our applications’s core logic, but rather acts like the glue that’s needed for pretty much every project.

A little example

I know what you’re thinking, “This is not from the stdlib…” just hold on for a second, this is from the discordgo pkg and it serves as a perfect example for the second case from above. If we look deeper into the code that deals with that handler variable we encounter something like this…

Not so pretty, right? And there are 37 more cases to just handle a single variable, and just so it stays in mind, here the pkg maintainers decided to expose 1 function and leave the hard work of type checking for themselves instead of exposing 44 different functions with similar names to the user. And all of that to add a simple handler.

The stdlib

In the stdlib you can find some pkgs that could reduce their API’s immensely if and just if something like generics existed for Go, examples:

sync/atomic

Contains 29 pkg funcs with names like AddT, CompareAndSwapT, where T could be Int32, Int64, Uint32, Uint64 and so on . . .

Almost literally the whole pkg API would be:

That just went from 29 functions with larger names to just 5 with shorter names.

sync.Map (Go 1.9+)

Yep, this awesome concurrent map is coming! with interface{} everywhere . . .

In this case, the only benefit is type safety since the API is simple enough.

math/rand

Very similar to the sync/atomic case, instead of Int, Intn, Int31, Int31n what about:

Same treatment goes for the rand.Rand type.

math/big

Maybe convert the Float, Int and Rat types into a general Number type and compute the operations depending on the generic.

And some others applicable cases are:

I also think that for example, let’s say we have this pretty common piece of code:

I believe if there were generics this kind of operations could be improved /optimized at compile time since the compiler knows what the format of the data looks like. Example below.

Same for all encoding/decoding stuff such as encoding/xml, encoding/csv is not included since all records are always returned in [][]string which means no reflection/type assertion at all.

What I’m trying to say is that the stdlib CAN be reduced and simplified in numerous places with the help of generics, and of course third-party pkgs as well. I hope this post at least serves as a clear example of what can be done with generics.

Topics of interest

More Related Stories