Go

Explain type sets. How do unions and intersections combine, and which interfaces can only be used as constraints?

Question 116HardGo 1.22 to 1.25

Every interface denotes a type set:

  • A method element gives the set of all types that have that method.
  • A union A | B gives the union of the two sets.
  • Elements on separate lines are intersected.

A type satisfies the constraint if it is in the set.

type SignedInt interface{ ~int | ~int32 | ~int64 }
type Stringer interface{ String() string }

// Intersection: named int-like types that ALSO have String()
type PrintableInt interface {
    SignedInt
    Stringer
}

// Empty type set: legal to declare, but no type can satisfy it
type Impossible interface {
    int
    string
}

Restrictions worth knowing:

  • An interface with type terms (int, ~int, a union) or with comparable is a constraint interface. It cannot be the type of a variable, field or parameter. var n SignedInt fails with "cannot use type SignedInt outside a type constraint".
  • A union term cannot be an interface that has methods, and it cannot be comparable.
  • Union terms (other than interfaces) must have disjoint type sets. int | ~int is an error because ~int already includes int.
  • A type parameter cannot itself be a union term. [T any, U T | int] is illegal.

What the interviewer wants to hear is that "an interface is a set of types" is the mental model, and that basic (method-only) interfaces are a special case.

More on Generics

All 36 Generics questions