Go error: cannot use generic type without instantiation

Issue

Studying Go generics, I’m running into an error I can’t seem to untangle. I’ve boiled it down to the simplest code:

type opStack[T any] []T

func main() {

    t := make(opStack)
    //  t := new(opStack)
    t = append(t, 0)
    fmt.Println(t[0])
}

In playground, this bonks at the make() call (and similarly on the new call that’s commented out) with the following error message:

cannot use generic type opStack[T any] without instantiation

But make() is an instantiating function. So, I expect I’m missing some syntactical subtlety. What is Go complaining about and what’s the needed correction?

Solution

Whenever you use a parametrized type, including anywhere a type argument is required, like in the built-in make, you must replace the type parameters in its definition with actual types. This is called instantiation.

t := make(opStack[int], 0)
t = append(t, 0)

A generic type must be instantiated also if you use it as a type argument to another generic type:

type Data[T any] struct {
    data T
}

d := Data[opStack[int]]{ data: []int{0, 1, 2} }

The relevant quotes from the language specs are (currently) in two different places, Type definitions:

If the type definition specifies type parameters, the type name denotes a generic type. Generic types must be instantiated when they are used.

and Instantiations

A generic function or type is instantiated by substituting type arguments for the type parameters. […]

In other programming languages, "instantiation" may refer to creating an instance of an object — in Go the term specifically refers to replacing type params with concrete types. In my view, the usage of the term is still consistent, although in Go it doesn’t necessarily imply allocation.


Note that you may call generic functions without explicit type arguments. Instantiation happens there too, simply the type arguments might all be inferred from the function arguments:

func Print[T, U any](v T, w U) { /* ... */ }

Print("foo", 4.5) // T is inferred from "foo", U from 4.5

Inference used to work also in generic types, with the restriction that the type parameter list had to be non-empty. However this feature has been disabled, so you must supply all type params explicitly.

type Vector[T any] []T 
// v := Vector[int]{} -> must supply T

type Matrix[T any, U ~[]T] []U 
// m := Matrix[int, []int]{} -> must supply T and U

Answered By – blackgreen

Answer Checked By – Marilyn (GoLangFix Volunteer)

Leave a Reply

Your email address will not be published.