Create me a two-parameter dispatcher Combiner with handlers for (Circle, Circle) and (Circle, Rectangle), demonstrating that parameter order matters and unmatched combinations fall back to the entry method.
← Dispatcher Validation · Ref: Q1245
EK9 dispatchers can resolve on multiple parameter types at once. With two parameters, the dispatcher matches on the runtime type of EACH parameter independently, so handler selection considers the full combination, not just the first parameter.
SHAPE HIERARCHY
Shape as abstract default operator ? Circle is Shape default operator ? Rectangle is Shape default operator ?
TWO-PARAMETER DISPATCHER
Combiner
combine() as dispatcher
->
s1 as Shape
s2 as Shape
<- rtn as String: "Generic"
combine()
->
s1 as Circle
s2 as Circle
<- rtn as String: "Circle-Circle"
combine()
->
s1 as Circle
s2 as Rectangle
<- rtn as String: "Circle-Rectangle"
The entry method takes both parameters as the parent type Shape. Each handler narrows BOTH parameters to specific subtypes.
DISPATCH BEHAVIOUR
combiner.combine(circle, circle) // "Circle-Circle" — exact match combiner.combine(circle, rectangle) // "Circle-Rectangle" — exact match combiner.combine(rectangle, circle) // "Generic" — no (Rectangle, Circle) handler combiner.combine(rectangle, rectangle) // "Generic" — no handler for this pair
KEY INSIGHT
Parameter ORDER matters: (Circle, Rectangle) and (Rectangle, Circle) are DIFFERENT dispatch keys. If you want them to behave the same, you must declare both handlers. Unhandled combinations fall through to the entry method's body, which acts as the default.
This is true multiple dispatch — found in CLOS, Julia, Common Lisp — but rare in mainstream languages. Java/C# require visitor or instanceof chains; EK9 makes it a one-liner per case.
See Q619 for two-parameter dispatch basics. See Q620 for hierarchy rules. See Q1244 for deep hierarchy single-parameter dispatch.
Example
defines module qa.dispatcher.twoparam defines class Shape as abstract default operator ? Circle is Shape default operator ? Rectangle is Shape default operator ? Combiner combine() as dispatcher -> s1 as Shape s2 as Shape <- rtn as String: "Generic" combine() -> s1 as Circle s2 as Circle <- rtn as String: "Circle-Circle" combine() -> s1 as Circle s2 as Rectangle <- rtn as String: "Circle-Rectangle" defines program TwoParamDispatchDemo() stdout <- Stdout() combiner <- Combiner() circle <- Circle() rectangle <- Rectangle() stdout.println(combiner.combine(circle, circle)) stdout.println(combiner.combine(circle, rectangle)) stdout.println(combiner.combine(rectangle, circle)) stdout.println(combiner.combine(rectangle, rectangle))
Common mistakes
E01082 — Multiple parameters are declared with a single '->' followed by an indented parameter block. Repeating '->' for each parameter is a parser-level syntax error. See ek9 -h E01082 for details.
Incorrect:
combine() as dispatcher -> s1 as Shape -> s2 as Shape
Correct:
combine() as dispatcher -> s1 as Shape s2 as Shape
Other ways to ask this
- Show me a dispatcher that resolves on TWO parameter types simultaneously.
- Implement a combine method that dispatches differently for different shape pairs.
- Build a multi-method-style dispatcher with two parameters in EK9.
- Write a dispatcher demonstrating asymmetric handler coverage on parameter pairs.
Coming from another language?
Java: nested instanceof or double-dispatch via visitor. Scala: pattern match on tuple (s1, s2) match { case (Circle, Circle) => ... }. Common Lisp / CLOS: defmethod with two specialised parameters — the inspiration. Julia: multimethod with type ascriptions on each parameter. EK9: native two-parameter dispatcher with cost-based selection on both arguments.
Keywords: dispatcher, two parameter, parameter order, fallback, asymmetric, combine, multiple dispatch