What happens if a dispatcher handler's parameter type is outside the hierarchy?

← Dispatcher Validation · Ref: Q614

Every dispatcher handler's parameter type must be a subtype of the dispatcher entry's parameter type. If a handler specifies a type that is not in the hierarchy, the compiler raises E05210.

WHY TYPE HIERARCHY MATTERS

Dispatchers route calls based on runtime type. The entry method declares a base type (e.g., Animal). Each handler declares a specific subtype (e.g., Dog, Cat). At runtime, the dispatcher checks the actual type and routes to the matching handler. If a handler type is not in the hierarchy, it can never match.

EXAMPLE OF THE ERROR

If the dispatcher entry takes Animal and a handler takes Vehicle, no Animal can ever be a Vehicle. The handler is unreachable and indicates a design error.

CORRECT PATTERN

All handlers must use subtypes of the entry's parameter type:

  handle() as dispatcher
    -> a as Animal
  handle()
    -> a as Dog        //OK: Dog extends Animal
  handle()
    -> a as Cat         //OK: Cat extends Animal

SEPARATE DISPATCHERS FOR SEPARATE HIERARCHIES

If you need to dispatch on multiple unrelated type hierarchies, create separate dispatchers. Each dispatcher handles one hierarchy.

See Q60 for dispatcher fundamentals. See Q615 for return type matching. See Q619 for two-parameter dispatchers.

Example

defines module qa.dispatchervalidation.hierarchy

  defines class

    Animal as abstract
      speak() as pure abstract
        <- rtn as String?
      default operator ?

    Dog extends Animal
      override speak() as pure
        <- rtn as String: "woof"
      default operator ?

    Cat extends Animal
      override speak() as pure
        <- rtn as String: "meow"
      default operator ?

    Bird extends Animal
      override speak() as pure
        <- rtn as String: "tweet"
      default operator ?

    //CORRECT: all handler types are in the Animal hierarchy
    AnimalHandler
      handle() as dispatcher
        -> animal as Animal
        <- rtn as String: "Animal: " + animal.speak()

      handle()
        -> animal as Dog
        <- rtn as String: "Dog says: " + animal.speak()

      handle()
        -> animal as Cat
        <- rtn as String: "Cat says: " + animal.speak()

      handle()
        -> animal as Bird
        <- rtn as String: "Bird says: " + animal.speak()

  defines function

    testHierarchyDispatch()
      handler <- AnimalHandler()

      dog <- Dog()
      cat <- Cat()
      bird <- Bird()

      require handler.handle(dog) == "Dog says: woof"
      require handler.handle(cat) == "Cat says: meow"
      require handler.handle(bird) == "Bird says: tweet"

Common mistakes

E50010 — The dispatcher entry takes Animal. A handler parameter type must be a subtype of Animal. Vehicle is completely unrelated and would never match at runtime. See ek9 -h E50010 for details.

Incorrect:

handle()
        -> vehicle as Vehicle

Correct:

handle()
        -> animal as Dog

E05220 — The dispatcher entry returns String. All handlers must return the same type. A handler returning Integer would create an inconsistent return type. See ek9 -h E05220 for details.

Incorrect:

handle()
        -> animal as Cat
        <- rtn as Integer: 0

Correct:

handle()
        -> animal as Cat
        <- rtn as String: "Cat says: " + animal.speak()
Other ways to ask this
  • What is E05210 in EK9?
  • Why must dispatcher handler types be in the same hierarchy?
  • Can a dispatcher handle unrelated types?

Coming from another language?

Java: method overloading doesn't check hierarchy, resolved at compile time. Kotlin: no runtime dispatcher, uses when + is checks. Rust: match on enum variants (closed hierarchy). Go: type switch operates on interfaces. EK9: E05210 enforces that all dispatcher handler parameter types are within the dispatch hierarchy.

Keywords: handler, extends, unrelated, subtype, dispatch, E05210, type, parameter, validate, dispatcher, hierarchy, ambiguity