How does method resolution work with overloading?
← Advanced Type System · Ref: Q255
EK9 uses a cost-based matching algorithm to resolve which overloaded method to call. Each potential match is assigned a numeric cost, and the method with the lowest total cost wins.
FIVE COST LEVELS
The compiler assigns costs based on how well each argument matches each parameter:
ZERO_COST (0.0) - exact type match, always preferred SUPER_COST (0.05) - superclass match, 0.05 per inheritance level TRAIT_COST (0.10) - trait match, 0.10 per trait level COERCION_COST (0.5) - type promotion via #^ operator HIGH_COST (20.0) - Any type match, universal fallback
HOW MATCHING WORKS
For each candidate method, the compiler sums the costs of all parameter matches. The match percentage is calculated as 100.0 minus totalCost. Higher percentage means better match. The method with the highest percentage (lowest cost) wins.
Examples:
Exact Integer match: cost 0.0, percentage 100.0% Superclass one level: cost 0.05, percentage 99.95% Trait match: cost 0.10, percentage 99.90% Promoted Integer to Float: cost 0.5, percentage 99.5% Any fallback: cost 20.0, percentage 80.0%
AMBIGUITY DETECTION
If two methods score within 0.001 of each other, the compiler reports an ambiguity error rather than guessing. This prevents subtle bugs where adding a new overload silently changes which method gets called.
DISPATCHER RESOLUTION ORDER
In a dispatcher, this cost system determines which overload handles each type:
1. Exact type match scores 100% - always called first 2. Parent class match scores near 100% - called for subtype 3. Trait match scores near 100% - called for implementor 4. Promotion match scores 99.5% - called after type widening 5. Any fallback scores 80% - called only when nothing else matches
MULTI-PARAMETER COSTS
With multiple parameters, costs are summed. A method with two exact matches (cost 0.0 + 0.0 = 0.0) beats a method with one exact and one promoted match (cost 0.0 + 0.5 = 0.5).
See Q24 for the dispatcher pattern. See Q25 for the promote operator and coercion cost. See Q254 for Any type and HIGH_COST. See Q60 for function dispatching. See Q258 for type coercion details.
Example
defines module qa.advancedtypes.methodresolution defines class // Three-level hierarchy for demonstrating SUPER_COST Shape as open default Shape() as pure override operator ? as pure <- rtn <- true Circle extends Shape as open default Circle() as pure SmallCircle extends Circle default SmallCircle() as pure // Class with two differently-named methods — no overloading Renderer // render accepts (Shape, Circle) render() -> first as Shape second as Circle require first? and second? // handleShape accepts (Circle, Shape) — different name, no ambiguity handleShape() -> first as Circle second as Shape require first? and second? defines program MethodResolutionDemo() stdout <- Stdout() shape <- Shape() circle <- Circle() small <- SmallCircle() renderer <- Renderer() // Exact match: render(Shape, Circle) cost 0.0 + 0.0 = 0.0 renderer.render(shape, circle) // SmallCircle matches Circle at SUPER_COST: cost 0.0 + 0.05 = 0.05 renderer.render(shape, small) // handleShape is a separate method — no overload ambiguity // circle matches Circle(0.0), small matches Shape at 0.10 renderer.handleShape(circle, small) stdout.println("Method resolution completed")
Common mistakes
E06140 — Renaming handleShape to render creates two crossed overloads: render(Shape,Circle) and render(Circle,Shape). Calling render(circle,small) then costs 0.10 for both overloads: circle to Shape(0.05)+small to Circle(0.05) vs circle to Circle(0)+small to Shape(0.10). Equal costs trigger E50210 METHOD_AMBIGUOUS. See ek9 -h E50210 for details.
Incorrect:
render(
Correct:
handleShape(
Other ways to ask this
- How does EK9 pick which overloaded method to call?
- What is cost-based method matching in EK9?
- How does the compiler resolve ambiguous method calls?
- What are the cost levels in EK9 method resolution?
Coming from another language?
Java: method overloading resolved at COMPILE time based on declared types, not runtime types. Most specific match wins per JLS rules. C++: overload resolution uses implicit conversion sequences ranked by category. Python: no method overloading, uses functools.singledispatch for single-argument dispatch. Rust: no method overloading at all, uses trait dispatch. Go: no method overloading. Kotlin: compile-time overload resolution similar to Java. Julia: multiple dispatch with specificity rules similar to EK9's cost model. EK9: cost-based RUNTIME resolution, five distinct cost levels, ambiguity detection within 0.001 tolerance, works with dispatchers for runtime type-based dispatch.
Keywords: handler, ambiguity, cost, type-system, visitor, overload, promotion, trait, method, percentage, type, zero, resolution, super, sealed, coercion, advanced, matching, dispatch