Immutable object 2026-10-24
An immutable object does not change its observable state after construction. Immutable fields prevent reassignment of their stored values, but fields containing references to mutable software objects do not automatically make the reachable software object graph immutable. Read-only generic producers can often support covariant type parameters; publicly writable fields generally cannot.
Subtype polymorphism lets a reference with a common supertype denote values of different implementing classes. A call through that reference uses dynamic dispatch to select the concrete implementation.
Parametric polymorphism defines an operation or data structure using type parameters, such as a collection with an element-type parameter. Instantiations retain type information while reusing one generic definition.
Ad hoc polymorphism, commonly expressed by method overloading, gives several implementations the same name but different parameter signatures. The compiler selects a suitable overload using the available static types. This selection differs from later dynamic dispatch on the receiver of a selected instance method. A programming language can support all three in one program.
val square: Fun[Int, Int] = new Fun[Int, Int] {
override def apply(x: Int): Int = x * x
}Parametric polymorphism occurs because the generic trait is specialized by choosing its argument and result types. Subtype polymorphism occurs because the anonymous implementing software class is used through a
Fun[Int, Int] reference; calls to its apply operation use the object interface contract and dynamic dispatch. Multiplication itself is not the second polymorphism needed for this explanation.For values whose mathematical squares fit in a signed 32-bit integer, the result is the ordinary square. Outside that range, the supplied integer return type cannot represent every mathematical square, and the multiplication follows Scala integer-overflow behavior. An implementation requiring exact mathematical results for all integer inputs would need a wider result type or an explicit overflow exception.
Give the two components independent upper type bounds and immutable fields:
final case class BoundedPair[+A <: Base, +B <: Base](first: A, second: B)Each component type must be a subtype of
Base, but the two need not be the same subtype. The pair's fields cannot be reassigned. Their read-only use permits covariant type parameters; the separate upper type bounds constrain admissible instantiations.[ref]Scala 2.13 basic declarations and definitions specification. Type Parameters and Variance Annotations: upper bounds restrict admissible arguments; immutable output positions permit covariance
The component accessors retain their precise static types. For example, a
BoundedPair[Derived, Base] exposes its first component as Derived, so derived-specific operations are available without a cast. A pair whose two fields are simply declared Base discards that distinction. Immutability here concerns the two stored references; it does not guarantee that the referenced software objects have immutable internal state.Official language specification covering type parameters, variance annotations, declarations and procedure syntax.
Type argument 2026-10-25