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).