What is an "instantiation cycle"? Why does this recursive generic function fail to compile?
Question 144HardGo 1.22 to 1.25
func Nest[T any](n int) {
if n > 0 {
Nest[[]T](n - 1)
}
}
func main() { Nest[int](3) }
Result: compile error instantiation cycle: T instantiated as []T.
Go instantiates generic code at compile time. Nest[int] needs Nest[[]int], which needs Nest[[][]int], and so on without end. The compiler cannot know that n bounds the recursion at run time, so it rejects any instantiation graph in which a type parameter grows. The same rule applies to types: type Node[T any] struct{ next *Node[[]T] } is rejected.
Recursion with the same or a fixed type argument is fine:
type TreeNode[T any] struct {
Val T
Left, Right *TreeNode[T]
}
func Depth[T any](n *TreeNode[T]) int {
if n == nil {
return 0
}
return 1 + max(Depth(n.Left), Depth(n.Right)) // T stays T
}
Languages that box everything (Java) or instantiate lazily at run time (C# with a JIT) accept polymorphic recursion like this. Go's stenciling model cannot. It is a good follow-up to the GC shape question.
More on Generics
- Q142What are generic type aliases (Go 1.24), and how do they differ from generic type definitions?
- Q143Are generic types covariant? Can a
Box[Dog]be used as aBox[Animal], or aBox[int]converted to aBox[MyInt]? - Q145What does this print? (
%Tand reflection on generic types) - Q146Write a generic fan-in
Mergefor channels. What are the concurrency pitfalls? - Q147How do you get a pointer to a literal value generically? Compare a
Ptr[T]helper with Go 1.26new(expr).