Go

Are generic types covariant? Can a Box[Dog] be used as a Box[Animal], or a Box[int] converted to a Box[MyInt]?

Question 143HardGo 1.22 to 1.25

No. Go generics are invariant. Each instantiation is a distinct named type, and there is no subtyping between instantiations, even when the type arguments are related by interface satisfaction or share an underlying type.

type Animal interface{ Sound() string }
type Dog struct{}
func (Dog) Sound() string { return "woof" }

type Box[T any] struct{ v T }
type MyInt int

var d []Dog
// var a []Animal = d                       // error: cannot use d ([]Dog) as []Animal
// var b Box[Animal] = Box[Dog]{}           // error: different types
// var x = Box[MyInt](Box[int]{})           // error: cannot convert Box[int] to Box[MyInt]

// Fix: copy element by element
func Upcast[T Animal](xs []T) []Animal {
    out := make([]Animal, len(xs))
    for i, x := range xs {
        out[i] = x
    }
    return out
}

Why the conversion fails: Box[int] has underlying type struct{ v int } and Box[MyInt] has struct{ v MyInt }. Those are different struct types, so the conversion rules do not apply. Covariance would be unsound for mutable containers anyway: if []Dog were a []Animal, you could store a Cat in it. Interviewers want "instantiations are unrelated types, convert explicitly".

More on Generics

All 36 Generics questions