Go

What is golang.org/x/exp/constraints, how does it relate to cmp.Ordered, and how do you define your own numeric constraint?

Question 137MediumGo 1.22 to 1.25

x/exp/constraints was the experimental home for common constraints: Signed, Unsigned, Integer, Float, Complex and Ordered. Only Ordered moved into the standard library, as cmp.Ordered in Go 1.21. The rest stayed in x/exp, because the team was unsure of the right granularity and naming. Many teams define their own constraints instead of taking an x/exp dependency.

// cmp.Ordered (std, Go 1.21):
// ~int | ~int8 | ~int16 | ~int32 | ~int64 | ~uint | ... | ~uintptr |
// ~float32 | ~float64 | ~string

type Integer interface {
    ~int | ~int8 | ~int16 | ~int32 | ~int64 |
        ~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64 | ~uintptr
}

type Float interface{ ~float32 | ~float64 }

type Number interface{ Integer | Float }

func Mean[T Number](xs []T) float64 {
    if len(xs) == 0 {
        return 0
    }
    var sum T
    for _, x := range xs {
        sum += x
    }
    return float64(sum) / float64(len(xs))
}

Gotchas:

  • sum of type T can overflow for small ints such as int8. Consider accumulating in float64 or int64.
  • cmp.Ordered includes ~string but not complex numbers or booleans.
  • Embedding constraint interfaces in a union (Integer | Float) is allowed only because neither has methods.

More on Generics

All 36 Generics questions