Questions: Ad Hoc Polymorphism and Function Overloading
5 questions to test your understanding
Score: 0 / 5
Question 1 Multiple Choice
A function `length` works on strings, lists, and arrays using a single uniform implementation that counts elements without inspecting type. A function `add` has one implementation for integers (ALU instruction) and a separate implementation for strings (memory allocation and copying). Which is ad hoc polymorphism?
ABoth `length` and `add` — any function that works across multiple types is ad hoc polymorphic
B`length` only — uniform behavior across types is the defining feature of ad hoc polymorphism
C`add` only — separate implementations per type is the defining feature of ad hoc polymorphism
DNeither — ad hoc polymorphism requires runtime dispatch to be valid
`add` is ad hoc polymorphism: the same name dispatches to fundamentally different code depending on argument types. `length` is parametric polymorphism: a single uniform implementation works for any container type without inspecting type information. The distinction is whether one implementation suffices for all types or whether each type gets its own bespoke code.
Question 2 Multiple Choice
The compiler encounters `foo(a, b)` where `foo` has overloads for (int, int) and (float, float). Both `a` and `b` are declared as `int`. The language allows implicit int-to-float promotion. How does overload resolution proceed?
AThe call is ambiguous because both overloads could apply after promotion
BThe (int, int) overload is selected as an exact match, with no promotion needed
CThe (float, float) overload is selected because float is the default numeric type
DThe call fails — ad hoc polymorphism does not permit implicit conversions
Overload resolution ranks matches: an exact type match beats any match requiring implicit promotion. Since (int, int) matches exactly, it is selected without ambiguity. The ambiguity in option A would arise only if two overloads tied in ranking (e.g., one requires int→float promotion on the first arg and the other on the second). Exact matches always take priority.
Question 3 True / False
Overload resolution for ad hoc polymorphism is performed at compile time, not at runtime.
TTrue
FFalse
Answer: True
This is a defining property of ad hoc polymorphism: the compiler determines which implementation to call based on the static (compile-time) types of the arguments. Once resolved, the call is bound to a specific function — there is no runtime overhead for dispatch. This distinguishes overloading from dynamic dispatch (virtual functions), where the target is determined at runtime via a vtable lookup.
Question 4 True / False
Ad hoc polymorphism and parametric polymorphism both use a single implementation shared across most applicable types.
TTrue
FFalse
Answer: False
This is the exact opposite of what distinguishes them. Parametric polymorphism uses one uniform implementation for all types without inspecting type information (e.g., `identity(x) = x`). Ad hoc polymorphism provides a distinct, bespoke implementation for each type — integer addition and string concatenation are fundamentally different operations even if both are spelled `+`.
Question 5 Short Answer
Explain why overload resolution can become ambiguous in a language that permits implicit type conversions, and how languages typically handle this.
Think about your answer, then reveal below.
Model answer: When implicit conversions are allowed, multiple overloads may be reachable from the same call site by applying different conversions. If no single overload is strictly better than all others (matches at least as well on every argument and strictly better on at least one), the compiler cannot choose and reports an ambiguity error. Languages like C++ rank candidates by conversion quality (exact match > promotion > standard conversion) and declare ambiguity only when two candidates tie at the top rank.
The problem is inherent to combining overloading with implicit conversion. For example, if `foo` has overloads (int, double) and (double, int), calling `foo(1, 2)` requires one implicit conversion for each — neither overload is strictly better. Rather than silently guessing, the compiler rejects the call as ambiguous. This is why language designers must carefully specify conversion rules and overload ranking to make resolution predictable.