Type inference

Wow, we have come so far already! We have created:

  • a generic function
  • a generic constraint
  • a new type definition that satifies the constraint

Now we can use a single function to sum various types of numeric values (Golang playground):

  1. func main() {
  2. fmt.Println(Sum([]int{1, 2, 3}...))
  3. fmt.Println(Sum([]id{1, 2, 3}...))
  4. fmt.Println(Sum(1, 2, 3.0))
  5. }

:exclamation::exclamation: Except instead of the expected output…

  1. 6
  2. 6
  3. 6

…the program fails to run with the following compiler error :exclamation::exclamation::

  1. ./prog.go:29:24: default type float64 of 3.0 does not match inferred type int for T

This error occurred because the Go compiler sees Sum[T Numeric](...T) T and needs to determine what concrete type should replace T.

In fact, have you noticed we have actually not had to specify the type for T in all our calls to Sum[T Numeric](...T) T on this page or any of the previous ones? This is because of a feature in the Go compiler known as, you guessed it, type inference.

The Go compiler attempts to infer the intended, concrete types for a generic function from its provided arguments by:

  • looking at the first instance of a generic type
  • determining the concrete type for the generic type
  • ensuring all other instances of the generic type share the same, concrete type

That is a gross oversimplification. The exact process by which type inference occurs is rather in-depth, and you are encouraged to read it. However, in the end the following key, takeaways will serve you well 90% of the time:

  • Type inference is a convenience feature
  • The Go compiler tries really hard to infer the intended types, but it does not always work when you think it should
  • If you are not sure why something written generically is not working, try providing the types explicitly

For that matter, how does one specify types explicitly?


Next: Explicit types