Write a dispatcher with a fallback handler for unmatched types.

← Design Patterns and Idioms · Ref: Q1122

The base dispatcher method IS the fallback:

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

If no specific overload matches the runtime type, the base method runs. For sealed traits with exhaustive handlers, the fallback is never reached.

See Q1121 for sealed trait dispatch. See Q1123 for deep hierarchy.

Example

defines module qa.designpatterns.dispatcherfallback

  defines class

    Shape as open
      name()
        <- rtn as String: "Shape"

    Circle extends Shape
      override name()
        <- rtn as String: "Circle"

    Square extends Shape
      override name()
        <- rtn as String: "Square"

    //No specific handler for this type — falls through to base
    Hexagon extends Shape
      override name()
        <- rtn as String: "Hexagon"

    ShapeDescriber

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

      describe()
        -> shape as Circle
        <- rtn as String: "It is a Circle"

      describe()
        -> shape as Square
        <- rtn as String: "It is a Square"

  defines program

    DispatcherFallbackDemo()
      stdout <- Stdout()
      describer <- ShapeDescriber()

      //Matched handlers
      stdout.println(describer.describe(Circle()))
      stdout.println(describer.describe(Square()))

      //Fallback — no specific handler for Hexagon
      stdout.println(describer.describe(Hexagon()))

Common mistakes

E01010 — The dispatcher base method IS the fallback. No 'default:' keyword — just provide the default return value.

Incorrect:

      describe() as dispatcher
        -> shape as Shape
        <- rtn as String?
        default:
          rtn: "Unknown"

Correct:

      describe() as dispatcher
        -> shape as Shape
        <- rtn as String: "Unknown shape"
Other ways to ask this
  • I need a dispatcher that handles known types and has a default for everything else
  • In Java I'd use a default case in a switch. Write the EK9 dispatcher default handler
  • Given an open hierarchy, dispatch known types and fall back for unknown ones
  • Handle specific types with dedicated handlers and catch-all for the rest

Coming from another language?

Java: switch default case or else branch. Kotlin: sealed when + else. EK9: the dispatcher base method is the default — no separate 'default' keyword needed.

Keywords: unmatched, catch-all, fallback, dispatcher, default