What happens with two-parameter dispatchers and type validation?
← Dispatcher Validation · Ref: Q619
EK9 supports true multiple dispatch: dispatchers can dispatch on two or more parameters simultaneously. The type hierarchy validation (E05210) applies to EACH dispatchable parameter independently.
MULTIPLE DISPATCH
A two-parameter dispatcher examines the runtime type of both arguments to select the most specific handler:
intersect() as dispatcher -> s1 as Shape, s2 as Shape intersect() -> s1 as Circle, s2 as Circle intersect() -> s1 as Circle, s2 as Rectangle
TYPE CHECKING PER PARAMETER
Each handler parameter must be a subtype of the corresponding dispatcher entry parameter. If the first entry parameter is Shape, all handlers' first parameters must extend Shape. The same applies to the second parameter.
COST CALCULATION
The total dispatch cost is the sum of costs for each parameter. A handler with Circle (cost 0.05) + Rectangle (cost 0.05) has total cost 0.10. Exact matches on both parameters (cost 0.00 + 0.00) always win.
AMBIGUITY WITH MULTIPLE PARAMETERS
Ambiguity (E05230) can occur when two handlers have the same total cost. For example, handler(Circle, Rectangle) and handler(Rectangle, Circle) both cost 0.10 when called with a type that matches both.
TRUE MULTIPLE DISPATCH
This is true multiple dispatch, a feature only Julia and Common Lisp natively support among mainstream languages. EK9 provides it with compile-time validation.
See Q60 for dispatcher fundamentals. See Q614 for single-parameter hierarchy. See Q616 for ambiguity detection.
Example
defines module qa.dispatchervalidation.twoparam defines class Shape as abstract name() as pure abstract <- rtn as String? default operator ? Circle extends Shape override name() as pure <- rtn as String: "circle" default operator ? Rectangle extends Shape override name() as pure <- rtn as String: "rectangle" default operator ? //CORRECT: Two-parameter dispatcher with all types in hierarchy CollisionDetector collides() as dispatcher -> s1 as Shape s2 as Shape <- rtn as String: `${s1.name()} vs ${s2.name()}` collides() -> s1 as Circle s2 as Circle <- rtn as String: "circle-circle collision" collides() -> s1 as Circle s2 as Rectangle <- rtn as String: "circle-rectangle collision" collides() -> s1 as Rectangle s2 as Rectangle <- rtn as String: "rectangle-rectangle collision" defines function testTwoParamDispatch() detector <- CollisionDetector() circle <- Circle() rect <- Rectangle() require detector.collides(circle, circle) == "circle-circle collision" require detector.collides(circle, rect) == "circle-rectangle collision" require detector.collides(rect, rect) == "rectangle-rectangle collision"
Common mistakes
E05210 — Each parameter in a multi-parameter dispatcher must be a subtype of the corresponding entry parameter. The entry takes Shape for both, so String is invalid for either parameter. See ek9 -h E05210 for details.
Incorrect:
collides()
->
s1 as Circle
s2 as String
Correct:
collides()
->
s1 as Circle
s2 as Rectangle
E05220 — All dispatcher handlers must return the same type as the entry method. The entry returns String, so a handler returning Integer is incompatible. See ek9 -h E05220 for details.
Incorrect:
collides()
->
s1 as Circle
s2 as Circle
<- rtn as Integer: 0
Correct:
collides()
->
s1 as Circle
s2 as Circle
<- rtn as String: "circle-circle collision"
Other ways to ask this
- Can EK9 dispatchers dispatch on multiple parameters?
- How does multi-parameter dispatch work in EK9?
- Does E05210 apply to each parameter in a dispatcher?
Coming from another language?
Java: no multiple dispatch (single dispatch via virtual methods). Python: functools.singledispatch (single parameter only). Julia: built-in multiple dispatch (most similar to EK9). Common Lisp: CLOS multi-methods. Rust: no dispatch mechanism. Kotlin: no multiple dispatch. EK9: true multiple dispatch with compile-time E05210 validation per parameter.
Keywords: ambiguity, E05230, visitor, multi, two, dispatch, multiple, E05210, validate, parameter, sealed, true, handler, cost