Method overloading 2026-10-24
Several callable methods share one name but differ in parameter signatures. In ordinary Scala calls, the compiler chooses among applicable alternatives using the receiver and arguments' static types, preferring a uniquely most-specific applicable alternative. Overloading is therefore a different step from method overriding and receiver-based dynamic dispatch.
To analyze an ordinary overloaded instance call, first enumerate members visible through the receiver's static type and choose the applicable signature using argument static types. Only then use the receiver's runtime type to select the effective override of that signature. This two-stage rule explains why changing a reference's declared type can change the selected overload even when every reference points to the same object. A super call selects the inherited implementation according to the language's superclass or linearization rules instead of recursively redispatching to the overriding body.
Method overloading gives one name several parameter signatures, such as show(A) and show(B). The compiler chooses an applicable signature using the receiver's static type and the argument expressions' static types, preferring a uniquely more specific applicable alternative. An argument whose type is a subtype of the parameter type is acceptable; ambiguous or inapplicable alternatives cause a compile-time error. The runtime type of an argument does not start a second overload search.
Method overriding replaces an inherited implementation of the same method signature. After overload selection, ordinary instance calls use dynamic dispatch on the receiver's runtime type to select the most-derived implementation of that signature. A concrete inherited method requires the override keyword in Scala; a super call invokes the corresponding superclass implementation instead of redispatching to the overriding body. In a trait stack, super follows the class's linearization.[ref][ref]
Permitted; returns "AB". A receiver of static type B exposes show(A) and show(B), but the argument's static type A is not a subtype of B. Only show(A) is applicable. Its effective implementation on the C receiver is B.show(A), which concatenates the superclass result "A" and "B".
Permitted; returns "AB". Through a receiver of static type A, only show(A) is visible. The argument's static type C is a subtype of A, so it can be passed to that method. Dynamic dispatch selects B.show(A) on the receiver object, exactly as in part (i). The argument's more specific type cannot expose overloads absent from the receiver's static type.
Permitted; returns "AB". The receiver's static type is A, which offers show(A). The argument also has static type A, so that signature is selected. All three variables refer to the same object of runtime type C; the most-derived implementation of show(A) is inherited from B. Its super.show(o) calls A.show(A), producing "A", and it appends "B". C overrides show(B), not this selected signature.
Permitted; returns "BC". Through static type B, both show(A) and show(B) accept an argument of type C; method overloading selects the more specific show(B). The receiver's runtime type is C, so dynamic dispatch invokes C.show(B). Its super.show(o) calls B.show(B), returning "B", and the override appends "C". The show(C) overload is not visible through receiver type B.
Permitted; returns "C". Both receiver and argument have static type C, so the most-specific applicable overload is show(C). That method is defined in C and returns its own one-letter result without calling super. The six results, in source order, are therefore AB, AB, AB, BC, BC, C.
Permitted; returns "BC". The receiver's static type is C, but the argument's static type is only B. Thus show(C) is inapplicable; among show(A) and show(B), the latter is more specific. Its implementation is C.show(B), whose superclass call returns "B" before "C" is appended. The argument happens to reference a C object, but method overloading uses its static type.
Using an interface or definition across multiple types. Subtype polymorphism dispatches through a common supertype; parametric polymorphism uses a type parameter uniformly; method overloading selects among signatures by static types in languages such as Scala. These mechanisms should be distinguished from genetic or materials-science polymorphism.
Static type 2026-10-24
The type assigned to a program expression during type checking. It controls which members and overloads are available at that expression. A reference with a broad static type can designate an object with a narrower runtime type; that does not expose additional overloads through the broad reference.