Bound type parameters

January 8, 2024

Type inference

Given a set of type equations, the type parameters to solve for are the type parameters of the functions that need to be instantiated and for which no explicit type arguments is provided. These type parameters are called bound type parameters. For instance, in the dedup example above, the type parameters P and E are bound to dedup. An argument to a generic function call may be a generic function itself. The type parameters of that function are included in the set of bound type parameters. The types of function arguments may contain type parameters from other functions (such as a generic function enclosing a function call). Those type parameters may also appear in type equations but they are not bound in that context. Type equations are always solved for the bound type parameters only.

Now I’m pretty sure there’s a typo in the above. I’m quite sure it means “type parameters S and E” not “P and E” (I’ll try to remember to submit a CL later to fix it…). So with that in mind, let’s continue.

Now let’s try to make sense of this, now, with some examples.

First, it references the dedup example we quoted yesterday. Here it is again:

// dedup returns a copy of the argument slice with any duplicate entries removed.
func dedup[S ~[]E, E comparable](S) S { … }

type Slice []int
var s Slice
s = dedup(s)   // same as s = dedup[Slice, int](s)

As it (almost) says, the type parameters S and E are said to be bound to dedup. Why does this matter?

Because there can be additional type parameters at play, if we use generic functions as arguments to generic functions. Let’s expand the example:

// sort orders the elements of a slice
func sort[X ~[]Y, Y comparable](X) X { … }

sort(dedup([]int{1, 2, 3, 2, 1}))

Now we have the generic dedup functioon being called, which has bound type parameters S and E as previously discussed. But its result is passed to sort, which itself has bound parameters X and Y. What is noteworthy is that S and E are not bound to sort.

Tomorrow we’ll plug this new concept into the nitty-gritty of the logic of type equation solutions. I hope you’re ready!

Quotes from The Go Programming Language Specification Version of August 2, 2023

Share this

Direct to your inbox, daily. I respect your privacy .

Unsure? Browse the archive .

Related Content

The many type equations

Type inference … Type inference supports calls of generic functions and assignments of generic functions to (explicitly function-typed) variables. So just to call out this point, made in passing: You cannot assign the result of a generic function to a generic, non-instantiated type, even if inferrence should be intuitive. Do demonstrate: type S[T ~int | ~float64] struct { Value T } func sum[V ~int | ~float32](a, b V) V { return a + b } // cannot use generic type S[T ~int | ~float64] without instantiation x := S{ Value: sum(int(1), int(2)), } Even though the type returned from sum() is obviously int, we cannot do this assignment.

Exact & loose type unification

Type unification … Unification uses a combination of exact and loose unification depending on whether two types have to be identical, assignment-compatible, or only structurally equal. The respective type unification rules are spelled out in detail in the Appendix. The precise definitions of “exact” and “loose” unification are buried in the appendix, and depend on the specific types involved. In general, I think it’s not terribly inaccurate to say that exact unification applies when the two types are identical, for composite types with identical structure (i.

Type unification

A couple of days ago we saw the spec reference the concept of “type unification”. Today we start through that explanation…. Type unification Type inference solves type equations through type unification. Type unification recursively compares the LHS and RHS types of an equation, where either or both types may be or contain bound type parameters, and looks for type arguments for those type parameters such that the LHS and RHS match (become identical or assignment-compatible, depending on context).