How does adding a concrete type handler resolve dispatcher ambiguity?
← Dispatcher Validation · Ref: Q870
When a class implements two traits and a dispatcher has handlers for both traits, dispatching that class is ambiguous (E05230) because both handlers match at equal cost (0.10 each). Adding a handler for the concrete type resolves the ambiguity because exact match costs 0.00.
THE PROBLEM
Duck implements Flyable and Swimmable. Handlers exist for both traits at cost 0.10 each. Dispatching Duck is ambiguous.
THE SOLUTION
Add a handler specifically for Duck (cost 0.00 — exact match). This always wins over trait handlers.
CORRECT PATTERN
process()
-> animal as Duck
<- rtn as String: animal.speak()
Exact match handler at cost 0.00 beats trait handlers at cost 0.10.
INCORRECT PATTERN (removes Duck handler)
Without the Duck handler, Duck matches both Flyable (0.10) and Swimmable (0.10) at equal cost. Ambiguity.
See Q616 for ambiguity basics. See Q617 for diamond trait dispatch.
Example
defines module qa.dispatchervalidation.ambiguity.resolution defines trait Flyable fly() as abstract <- rtn as String? Swimmable swim() as abstract <- rtn as String? defines class Animal as abstract speak() as abstract <- rtn as String? default operator ? Dog extends Animal override speak() <- rtn as String: "woof" Duck extends Animal with trait of Flyable, Swimmable override speak() <- rtn as String: "quack" override fly() <- rtn as String: "flapping" override swim() <- rtn as String: "paddling" override operator ? as pure <- rtn as Boolean: true <?- Dispatcher with handlers for Animal (base), Flyable, Swimmable, and Duck (concrete). The Duck handler resolves ambiguity. -?> AnimalProcessor process() as dispatcher -> animal as Animal <- rtn as String: animal.speak() process() -> animal as Dog <- rtn as String: animal.speak() process() -> creature as Flyable <- rtn as String: creature.fly() process() -> creature as Swimmable <- rtn as String: creature.swim() //Duck handler resolves ambiguity (cost 0.00 beats trait cost 0.10) process() -> animal as Duck <- rtn as String: animal.speak() defines function testAmbiguityResolution() processor <- AnimalProcessor() dog <- Dog() duck <- Duck() require processor.process(dog) == "woof" require processor.process(duck) == "quack"
Common mistakes
E05230 — Without the Duck-specific handler, Duck matches both Flyable and Swimmable at equal cost (0.10 each). The dispatcher cannot choose. Add a concrete type handler to resolve. See ek9 -h E05230 for details.
Incorrect:
//Duck handler removed — ambiguity not resolved
Correct:
//Duck handler resolves ambiguity (cost 0.00 beats trait cost 0.10) process() -> animal as Duck <- rtn as String: animal.speak()
Other ways to ask this
- What triggers E05230 DISPATCHER_HANDLER_AMBIGUITY?
- How do I fix dispatcher ambiguity for types implementing multiple traits?
- Why does replacing a concrete handler with a trait handler cause ambiguity?
Coming from another language?
Java: method overloading resolved at compile time, no runtime dispatch ambiguity. C++: multiple inheritance ambiguity resolved with virtual base classes. Python: C3 linearization provides deterministic ordering. Kotlin: compiler error for interface default method conflicts. EK9: E05230 detects dispatch ambiguity at compile time, requires structural resolution.
Keywords: E05230, cost, trait, resolution, handler, dispatcher, ambiguity, concrete, duck