Home > Back-end >  Instantiation failure caused by function value with approximate constraint
Instantiation failure caused by function value with approximate constraint

Time:07-22

func GAddAll[E int, S ~[]E](e E, s S) S {
   copyS := make(S, len(s))
   for i, v := range s {
   copyS[i] = v   e
   }
   return copyS
}

For the above code, if I instantiate it like this, it will give an error when running(cannot infer S)

b := GAddAll[int]
fmt.Printf("%v", b(3, []int{1, 2}))

But it works fine like this

fmt.Printf("%v", GAddAll[int](3, []int{1, 2}))

I want to know why.

CodePudding user response:

Instantiation fails because S ~[]E has an approximate constraint, and there isn't enough type information to instantiate S.

When you assign the function value with:

b := GAddAll[int]

the function is already being instantiated. Quoting the spec:

A generic function that is is not called requires a type argument list for instantiation; if the list is partial, all remaining type arguments must be inferrable.

However S isn't inferrable. The only information available to the compiler is the type parameter E. After a first pass of substitution, the compiler is only able to infer the constraint ~[]E, which is now ~[]int, but the type argument S is still unknown.

Given that approximate type sets with tilde (~) are virtually infinite, there's no way to conclusively determine what S is — it could be type FooSlice []int — and instantiation fails.

So if you need to pass around the function value, you must instantiate by supplying both type parameters:

b := GAddAll[int, []int] // ok
fmt.Printf("%v", b(3, []int{1, 2}))

Instead with the call expression:

GAddAll[int](3, []int{1, 2})

the compiler still can't infer S from the type argument int, but it can infer it from the non-type argument []int{1,2}, and then instantiate the function.

A generic function that is called may provide a (possibly partial) type argument list, or may omit it entirely if the omitted type arguments are inferrable from the ordinary (non-type) function arguments.

As a clarification, if you were to remove the tilde from the S ~[]E, like this:

func GAddAll[E int, S []E](e E, s S) S {}

inference would succeed by supplying only E, because the type set of S's constraint would have cardinality 1 (an exact type).

  • Related