Go

What does the ~ (tilde) token mean in a constraint? What happens without it?

Question 115MediumGo 1.22 to 1.25

~T means "every type whose underlying type is T". Without the tilde, only the exact type T itself matches. Named types such as type Celsius float64 or time.Duration (underlying int64) are then rejected.

type Exact interface{ int64 }
type Approx interface{ ~int64 }

func A[T Exact](v T) T  { return v }
func B[T Approx](v T) T { return v * 2 }

// A(time.Second)            // error: time.Duration does not satisfy Exact
fmt.Println(B(time.Second))  // 2s  (result is time.Duration, not int64)

type Name string
func Upper[T ~string](s T) T { return T(strings.ToUpper(string(s))) }
fmt.Printf("%T\n", Upper(Name("go"))) // main.Name

Rules and gotchas:

  • In ~T, T must be its own underlying type. ~time.Duration is illegal, and so is ~error or any other interface.
  • Inside the function you usually need an explicit conversion to call non-generic APIs, as in string(s) above. The result then keeps the caller's named type.
  • Library constraints such as cmp.Ordered use ~ everywhere. That is why sorting works on named types.

Interviewers want to hear that you understand the difference between underlying type and named type, and why the result type is preserved.

More on Generics

All 36 Generics questions