A call f(3, "hello") is made where both f(int, Object) and f(Object, String) are visible and applicable. Which function does the compiler select?
Af(int, Object) — it matches the first argument exactly, which is the tiebreaker
Bf(Object, String) — it matches the second argument exactly, which takes precedence
Cf(int, Object) — it was declared first in the source code
DNeither — the call is ambiguous because no candidate is more specific than the other across all parameters
Specificity requires one candidate to be at least as specific as the other in every parameter, with at least one strictly more specific. f(int, Object) wins on the first parameter (int is more specific than Object) but loses on the second (Object is less specific than String). f(Object, String) wins on the second but loses on the first. Neither dominates the other, so the compiler reports an ambiguous call and refuses to choose. Declaration order is not a tiebreaker in most languages — the compiler would be making an arbitrary choice the programmer likely didn't intend.
Question 2 Multiple Choice
In overload resolution, candidate A is considered 'more specific' than candidate B for a given call if:
AA's function body executes in fewer steps than B's at runtime
BEvery argument at the call site requires fewer or no conversions to match A's parameter types compared to B's parameter types
CAll of A's parameter types are supertypes of B's parameter types
DA is declared in the same class as the call site, while B is inherited
Specificity is about conversion distance: an exact type match (no conversion) beats a widening match (e.g., int → long), which beats a subtype match (String → Object). A is more specific than B if every argument-to-parameter conversion for A requires less widening than the corresponding conversion for B. Importantly, 'more specific' requires A to win on every parameter — if A wins on some and loses on others, neither is more specific, and the call is ambiguous. Runtime performance and declaration location are irrelevant to type-based specificity.
Question 3 True / False
If f(int x) and f(Object x) are both defined, calling f(42) will select f(Object x) because Object is the most general type and can accept any argument without error.
TTrue
FFalse
Answer: False
Overload resolution selects the MOST SPECIFIC applicable candidate, not the most general. f(int) matches the literal 42 exactly with no conversion, while f(Object) requires widening (boxing the int to an Integer, then treating it as Object). More specific beats less specific, so f(int) is selected. If f(Object) were always preferred because it 'can always accept anything,' there would be no point in declaring more specific overloads — the language intentionally rewards specificity to make overloaded APIs behave intuitively.
Question 4 True / False
In overload resolution, an 'ambiguous call' compile error means the compiler found no applicable candidates for the given argument types.
TTrue
FFalse
Answer: False
Ambiguity means the opposite: the compiler found multiple applicable candidates but could not determine which is most specific. If no candidates are applicable, the error is 'no matching function' (or similar), not ambiguity. Ambiguous calls typically occur when two candidates each win on a different subset of parameters, so neither dominates the other. The compiler rejects the call rather than arbitrarily choosing one, forcing the programmer to resolve the ambiguity through explicit casting, renaming, or rearranging declarations.
Question 5 Short Answer
Explain why overload resolution can produce an 'ambiguous call' error even when the programmer clearly intended one specific function to be called, and what the compiler is protecting against by refusing to guess.
Think about your answer, then reveal below.
Model answer: Ambiguity arises when multiple candidates are all applicable but none is strictly more specific than the others across all parameter positions. The compiler cannot read programmer intent — it can only apply the specificity rules mechanically. If it guessed (e.g., by declaration order), a refactoring that reorders functions or adds a new overload could silently change which function runs, introducing subtle bugs. By reporting an error instead, the compiler forces the programmer to make intent explicit — typically by adding a cast to the argument — ensuring the choice is stable and visible. This is the same philosophy as rejecting ambiguous grammar in parsing: the safe failure is preferable to a silent wrong choice.
The deeper lesson is that overload resolution is a static algorithm operating only on types, not values or semantics. When types don't establish a clear winner, the programmer must add type information (via casting) to break the tie. This keeps the resolution deterministic and immune to source-code ordering.