Type safety means that program operations respect the constraints imposed by their types. Generic data structures can make those constraints enforceable at compile time, rather than leaving incompatible assignments to fail later. section 1.0 section 3.10
Variance exposes the boundary clearly. A mutable IList<T> cannot safely be treated as an IList of a broader type: adding a Giraffe through that view can place an invalid value into a list of Tigers. C# therefore restricts covariant type parameters to output positions. section 2.3
Immutability removes the mutation that causes the violation, but Push(T) still consumes T. Moving Push into an extension method leaves the interface read-only and permits safe covariance through IEnumerable<T>, Peek(), and Pop(). section 2.3
A covariant immutable stack
An IImStack<Tiger> can be assigned to IImStack<Animal>, after which an immutable Push extension can add a Giraffe. The original stack remains structurally safe because the interface exposes no mutating Add operation. section 2.3







