A relationship in which values of one type can be used wherever values of a broader type are required, subject to the language's compatibility rules. In nominal object-oriented programming, extending a class or implementing a trait establishes relevant subtype relationships. Type variance describes how these relationships lift through parameterized types.
A lower bound requires an admissible type argument to be a supertype of a specified type. In Scala, [V >: U] means . For an immutable software class covariant in U, a method accepting a new output value cannot consume U directly in a contravariant method-parameter position. Instead, add[V >: U](x: V) accepts a possibly wider value and returns a fresh instance parameterized by V. The original narrower instance remains unchanged. The variance-position rule and subtyping justify this widening; a bound alone does not authorize mutating an existing instance through a widened reference.[ref]
An upper type bound requires the type argument assigned to to be a subtype of . Two independently bounded parameters can retain different precise component types while sharing the same upper bound. Bounds and type variance answer different questions: admissible arguments versus subtyping between instantiations.
A type parameter can be bounded using a type expression containing that same parameter. In Scala, [T <: Ordered[T]] requires each admissible T to provide comparison with another T. This gives a generic minimum scan access to x < y for two elements of type T. An arbitrary unrelated upper bound would not establish the needed argument type.
A type is a supertype of when is a subtype of . A lower type bound requires an admissible type argument to lie above a specified type in this subtyping relation.
Subtype polymorphism lets a value implementing a more specific type be used through a common supertype object interface. Calls to overridable instance methods can select implementations by dynamic dispatch. Behavioral subtyping additionally requires the concrete implementation to honor the common contract, including preconditions, postconditions and state invariants; structural access to object method names alone does not establish that guarantee.
Substitution of an implementation for an interface while preserving its behavioral contracts, not just method types. Strengthening a method's precondition or weakening its postcondition can invalidate substitution. A nonnegative immutable refinement of a signed count value can inherit an exact subtraction returning the signed supertype; changing that same operation into truncated subtraction would not satisfy its parent's exact-difference postcondition.

Articles by others on the same topic (0)

There are currently no matching articles.