Go generics are not bad

When programming, we often need to write ‘generic’ functions where the exact data type is not important. For example, you might want to write a simple function that sums up numbers.

Go lacked this notion until recently, but it was recently added (as of version 1.18). So I took it out for a spin.

In Java, generics work well enough as long as you need “generic” containers (arrays, maps), and as long as stick with functional idioms. But Java will not let me code the way I would prefer. Here is how I would write a function that sums up numbers:

    int sum(int[] v) {
        int summer = 0;
        for(int k = 0; k < v.length; k++) {
            summer += v[k];
        }
        return summer;
    }

What if I need to support various number types? Then I would like to write the following generic function, but Java won’t let me because Java generics only work with classes not primitive types.

    // this Java code won't compile
    static <T extends Number>  T sum(T[] v) {
        T summer = 0;
        for(int k = 0; k < v.length; k++) {
            summer += v[k];
        }
        return summer;
    }

Go is not object oriented per se, so you do not have a ‘Number’ class. However, you can create your own generic ‘interfaces’ which serves the same function. So here is how you solve the same problem in Go:

type Number interface {
  uint | int | float32 | float64
}


func sum[T Number](a []T) T{
    var summer T
    for _, v := range(a) {
        summer += v
    }
   return summer
}

So, at least in this one instance, Go generics are more expressive than Java generics. What about performance?

If I apply the above code to an array of integers, I get the following tight loop in assembly:

pc11:
        MOVQ    (AX)(DX*8), SI
        INCQ    DX
        ADDQ    SI, CX
        CMPQ    BX, DX
        JGT     pc11

As far as Go is concerned, this is as efficient as it gets.

So far, I am giving an A to Go generics.

Published by

Daniel Lemire

A computer science professor at the University of Quebec (TELUQ).

6 thoughts on “Go generics are not bad”

  1. This is the simplest case only, and could be done with C preprocessor macros. Simply by substituting Number by the four permitted values, compiling it four times. But what if you had a high precision number type instead?
    Any of the many “template engines” can be used to generate such code in Java (and most of the “primitive collections” libraries work this way.
    I believe the actual test case for expressability of generics is when you have polymorphism at the same time, and the type may not yet known at compilation time.

    What impressed me a bit more is the expressivity of Rust with it’s numeric traits – you could express that you want to fail on overflow, use a saturating add, etc. – but honestly that takes the fun out of it eventually. And how many “saturating add” types do you have? Pretty much only the primitive integers, not even floats…

  2. The more I (try to) use them, the more I realize how incomplete they are, and how bad they sometimes are. To everyone: First google what’s all missing and virtually impossible, it will save you time.

Leave a Reply

Your email address will not be published.

To create code blocks or other preformatted text, indent by four spaces:

    This will be displayed in a monospaced font. The first four 
    spaces will be stripped off, but all other whitespace
    will be preserved.
    
    Markdown is turned off in code blocks:
     [This is not a link](http://example.com)

To create not a block, but an inline code span, use backticks:

Here is some inline `code`.

For more help see http://daringfireball.net/projects/markdown/syntax

You may subscribe to this blog by email.