Erik Explores

Erik Explores

Share this post

Erik Explores
Erik Explores
Go Generics Beat Java

Go Generics Beat Java

The Java and C# crowds are running out of reasons to hate Go

Erik Engheim's avatar
Erik Engheim
Jul 26, 2022
∙ Paid
1

Share this post

Erik Explores
Erik Explores
Go Generics Beat Java
Share

Go is a much loved and hated language. Dunking on Go for not having generics has been almost like a sporting event in the global developer community. With the launch of Go generics, the Go hating community will run into a bit of an identity crisis. The lack of generics has been something everybody could rally around. Today not only does Go have generics but their generics is also pretty good. In fact, Go generics is in many ways better than generics in Java and C#.

Let us look at why with a simple example often used to demonstrate generics in Go. In the pre-generics age, we might write a Sum function in Go like this:

func Sum(numbers int) int {
    var total int
    for _, x := range numbers {
        total += x
    }
    return total
}

This solution is limiting because we can only sum integers. What if we want to sum floating-point numbers or complex numbers instead? In the before-time, we had to duplicate code. Today, we can wave the magic generics wand and write:

type Number interface {
    int16 | int32 | int64 | float32| float64
}

func Sum[T Number](numbers []T) T {
    var total T
    for _, x := range numbers {
        total += x
    }
    return total
}

In the code example, we are stating that any type which is an integer or floating-point number of different bit-length satisfies the Number interface. We can implement this code more elegantly by importing ready-made interfaces from the golang.org/x/exp/constraints package:

import  "golang.org/x/exp/constraints"

type Number interface {
	Integer | Float
}

This code example is a pretty simple and obvious use of generics. Regardless of what programming language I use, working with generics for simple data types like integers and floating-point numbers is my bread and butter. Yet, this obviously useful code isn't even possible to write in Java:

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

Until Microsoft releases the next version of C#, I believe you cannot do this in C# either. Both Java and C# have made primitive types second class citizens, which makes obviously useful code impossible to implement without ugly hacks killing performance. The Go code example actually translates into hyperefficient machine code:

sum:
    MOVD  ZR, R0       // start index at zero
    MOVD  ZR, R3       // zero out total
    JMP	  compare
    
addup:    
    MOVW  (R1)(R0<<2), R4
    ADD	  $1, R0, R0   // increment index
    ADD	  R4, R3, R3   // add to total

compare:    
    CMP   R0, R2       // are we at end of loop
    BGT	  addup        // branch greater than
    MOVD  R3, R0       // put total in return reg
    RET	  (R30)

The assembly code is ARM64, generated using the cross-compiler functionality of the Go build tools. You can run this line:

❯ env GOOS=linux GOARCH=arm64 go build -gcflags -S \ 
      generic-sum.go 2> generic-sum.S

Type Erasure in Go and Java

In Java, type information is not preserved after compilation. We refer to this fact as type erasure. The follow code is a simple demonstration of the consequences of type erasure in Java. You can see that despite the fact that Array<Integer> and Array<Float> should be treated as different types at runtime, Java cannot pick that up. The class is the same.

public class Array<T extends Number> {
    // ...
};

Array<Integer> integers = new Array<Integer>();
Array<Float> floats = new Array<Float>();

// evaluates to true
if (integers.getClass() == floats.getClass()) { 
    System.out.println("they're equal");
}

The Go type system does not have this problem. It correctly identifies Array[int64] and Array[float64] as different types at runtime.

Keep reading with a 7-day free trial

Subscribe to Erik Explores to keep reading this post and get 7 days of free access to the full post archives.

Already a paid subscriber? Sign in
© 2025 Erik Engheim
Privacy ∙ Terms ∙ Collection notice
Start writingGet the app
Substack is the home for great culture

Share