How does EK9 check dispatcher return type compatibility?

← Dispatcher Validation · Ref: Q615

All dispatcher handlers must return the same type as the dispatcher entry method (or a covariant subtype). If a handler returns a different, incompatible type, the compiler raises E05220.

WHY RETURN TYPES MUST MATCH

Callers invoke the dispatcher without knowing which handler will execute. The return type must be consistent so the caller can use the result regardless of which handler was selected at runtime.

EXACT MATCH

The simplest approach is to use the same return type for all handlers:

  describe() as dispatcher
    -> shape as Shape
    <- rtn as String: "shape"
  describe()
    -> shape as Circle
    <- rtn as String: "circle"

VOID DISPATCHERS

Dispatchers with no return type (void) require all handlers to also have no return type.

WHAT TO DO

If all handlers should return the same type: ensure exact match. If you need handler-specific return types: consider restructuring to return a common base type or using a wrapper.

See Q60 for dispatcher fundamentals. See Q614 for parameter type validation. See Q616 for dispatcher ambiguity.

Example

defines module qa.dispatchervalidation.returntypes

  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: All handlers return String (matching dispatcher entry)
    ShapeDescriber
      describe() as dispatcher
        -> shape as Shape
        <- rtn as String: "Shape: " + shape.name()

      describe()
        -> shape as Circle
        <- rtn as String: "Circle with round edges"

      describe()
        -> shape as Rectangle
        <- rtn as String: "Rectangle with four sides"

    //CORRECT: Void dispatcher (no return type for any handler)
    ShapePrinter
      print() as dispatcher
        -> shape as Shape
        content <- "Printing: " + shape.name()
        require content?

      print()
        -> shape as Circle
        content <- "Printing circle"
        require content?

      print()
        -> shape as Rectangle
        content <- "Printing rectangle"
        require content?

  defines function

    testReturnTypeMatch()
      describer <- ShapeDescriber()
      circle <- Circle()
      rect <- Rectangle()

      require describer.describe(circle) == "Circle with round edges"
      require describer.describe(rect) == "Rectangle with four sides"

    testVoidDispatcher()
      printer <- ShapePrinter()
      printer.print(Circle())
      printer.print(Rectangle())

Common mistakes

E05220 — The dispatcher entry returns String. A handler returning Integer is incompatible. All handlers must return the same type as the entry method. See ek9 -h E05220 for details.

Incorrect:

describe()
        -> shape as Circle
        <- rtn as Integer: 42

Correct:

describe()
        -> shape as Circle
        <- rtn as String: "Circle with round edges"

E50010 — The dispatcher entry dispatches on Shape. A handler for an unrelated type Animal is outside the Shape hierarchy and can never match. See ek9 -h E50010 for details.

Incorrect:

describe()
        -> animal as Animal

Correct:

describe()
        -> shape as Rectangle
Other ways to ask this
  • What is E05220 in EK9?
  • Must all dispatcher handlers return the same type?
  • Can dispatcher handlers have different return types?

Coming from another language?

Java: method overloading requires exact return type match (not covariant). Kotlin: when expressions can return a common type. Rust: match arms must return same type. Scala: pattern matching returns common supertype. EK9: E05220 enforces return type compatibility across all dispatcher handlers.

Keywords: handler, covariant, return, E05220, compatible, dispatch, match, type, consistent, dispatcher, validate, ambiguity