What happens when a dispatcher entry and handler have different purity?
← Dispatcher Validation · Ref: Q612
All dispatcher handlers must match the purity of the dispatcher entry method. If the entry is 'as pure', every handler must also be 'as pure'. If the entry is non-pure, handlers must be non-pure. A mismatch raises E05170.
WHY PURITY MUST MATCH
Callers of the dispatcher expect consistent behavior. If a dispatcher is declared pure, the caller relies on that guarantee for all possible dispatch targets. A non-pure handler would violate that contract at runtime, depending on which type is passed.
PURE DISPATCHER PATTERN
Mark both the entry and all handlers as pure:
describe() as pure dispatcher -> item as Item <- rtn as String: $item describe() as pure -> item as Book <- rtn as String: "Book: " + item.title()
NON-PURE DISPATCHER PATTERN
Omit 'as pure' from both entry and handlers:
process() as dispatcher -> item as Item process() -> item as Book stdout.println(item.title())
MIXING IS FORBIDDEN
You cannot have a pure entry with a non-pure handler, or vice versa. The compiler checks every handler against the entry's purity.
See Q560 for purity basics. See Q566 for pure method restrictions. See Q60 for dispatcher fundamentals. See Q620 for dispatcher hierarchy rules.
Example
defines module qa.dispatchervalidation.purity defines class Item as abstract name() as pure abstract <- rtn as String? default operator ? Book extends Item title <- "untitled" Book() -> title as String this.title: title override name() as pure <- rtn as String: title default operator ? Magazine extends Item issue <- "unknown" Magazine() -> issue as String this.issue: issue override name() as pure <- rtn as String: issue default operator ? //CORRECT: pure dispatcher with all pure handlers PureCatalog describe() as pure dispatcher -> item as Item <- rtn as String: item.name() describe() as pure -> item as Book <- rtn as String: "Book: " + item.name() describe() as pure -> item as Magazine <- rtn as String: "Magazine: " + item.name() defines function testPureDispatcher() catalog <- PureCatalog() book <- Book("EK9 Guide") mag <- Magazine("Tech Monthly") bookResult <- catalog.describe(book) magResult <- catalog.describe(mag) require bookResult == "Book: EK9 Guide" require magResult == "Magazine: Tech Monthly"
Common mistakes
E05170 — The dispatcher entry describe is declared as pure. Every handler must also be pure. Omitting as pure on a handler creates a purity mismatch. See ek9 -h E05170 for details.
Incorrect:
describe()
-> item as Book
Correct:
describe() as pure -> item as Book
E50010 — Each handler parameter type must be a subtype of the dispatcher entry parameter type Item. A handler for an unrelated type like Vehicle is outside the hierarchy. See ek9 -h E50010 for details.
Incorrect:
describe() as pure -> vehicle as Vehicle
Correct:
describe() as pure -> item as Magazine
Other ways to ask this
- What is E05170 in EK9?
- Must dispatcher handlers match purity of the entry method?
- Can a pure dispatcher have non-pure handlers?
Coming from another language?
Java: no purity concept, no dispatch purity checking. Kotlin: no purity enforcement on dispatchers. Haskell: all functions pure by default, dispatch via type classes. Rust: trait methods can be effectful or pure, but no dispatch purity contract. EK9: E05170 enforces consistent purity across all dispatcher handlers.
Keywords: match, pure, consistent, dispatcher, E05170, side-effect, entry, dispatch, validate, immutable, purity, contract, handler, ambiguity