// HACKER NEWS — CYBERSECURITY
Generic Methods in Go 1.27
An explanation of generic methods in Go, covering method-level type parameters and why dynamic dispatch prevents them from being declared inside interfaces.
When Go 1.18 introduced Generics in 2022, it brought generic type parameters to functions and structs, but left out methods. With the release of Go 1.27, this long-standing limitation has been removed. Methods can now define their own type parameters without adding them to the receiving struct.
If you want to create a graph node that holds a generic value, you might implement it like this:
Imagine adding a method Map that transforms a node of type T into a node of another type U. Prior to Go 1.27, you were forced to add U directly to the Node struct itself:
Adding U to the struct itself is bad design because U is a type parameter specific to Map. Even though other methods wouldn’t use U, they still had to keep it in their receiver declarations.
The only workaround was to implement Map as a package-level function instead of a method, since functions could define their own type parameters. But methods couldn’t, leading to awkward and non-idiomatic code API designs.
Starting in Go 1.27, U can be defined exclusively on the Map method:
The answer lies in how generics are implemented in Go. The compiler handles generics primarily using monomorphization, meaning it will create a copy of generic structs or functions for every specific type they’re used with. Because at some point, the abstract concept of generics needs to be translated to straight-forward machine code.
However, Go’s interface system works at runtime. The specific type of a value passed into an interface parameter is resolved while the program runs. This dynamic dispatch clashes with generics being resolved at compile time. Consider what would happen if we wanted to declare our Map method in an interface:
To make this work, the runtime would either need a Just-In-Time compiler to generate machine code for specific types on the fly, or it would need to create said copies for every possible type upfront, resulting in a massively bloated binary.