Create me a dispatcher method for a sealed Shape trait that has Circle, Square and Triangle handlers, demonstrating exhaustive runtime dispatch.
← Dispatcher Validation · Ref: Q1236
A dispatcher method declared with 'as dispatcher' resolves at runtime to the most specific overload based on the actual parameter type. When the parameter type is a sealed trait declared with 'allow only', you can write one handler per permitted type and the compiler ensures exhaustive coverage.
SEALED TRAIT
Shape allow only Circle, Square, Triangle name() as abstract <- rtn as String?
IMPLEMENTING CLASSES
Circle with trait of Shape override name() <- rtn as String: "Circle"
Square with trait of Shape override name() <- rtn as String: "Square"
Triangle with trait of Shape override name() <- rtn as String: "Triangle"
DISPATCHER ENTRY AND HANDLERS
The entry takes the trait type; each handler takes a permitted concrete type:
ShapeProcessor
describe() as dispatcher
-> shape as Shape
<- rtn as String: "Unknown"
describe()
-> shape as Circle
<- rtn as String: "Handled Circle"
describe()
-> shape as Square
<- rtn as String: "Handled Square"
describe()
-> shape as Triangle
<- rtn as String: "Handled Triangle"
USAGE
processor <- ShapeProcessor()
stdout.println(processor.describe(Circle()))
stdout.println(processor.describe(Square()))
stdout.println(processor.describe(Triangle()))
Each call selects the handler whose parameter most closely matches the runtime type. The 'allow only' clause means the compiler can verify ALL permitted types have a handler.
See Q618 for sealed exhaustive dispatch rules. See Q612 for purity matching. See Q60 for dispatcher fundamentals.
Example
defines module qa.dispatcher.sealedshape defines trait Shape allow only Circle, Square, Triangle name() as abstract <- rtn as String? defines class Circle with trait of Shape override name() <- rtn as String: "Circle" Square with trait of Shape override name() <- rtn as String: "Square" Triangle with trait of Shape override name() <- rtn as String: "Triangle" ShapeProcessor describe() as dispatcher -> shape as Shape <- rtn as String: "Unknown" describe() -> shape as Circle <- rtn as String: "Handled Circle" describe() -> shape as Square <- rtn as String: "Handled Square" describe() -> shape as Triangle <- rtn as String: "Handled Triangle" defines program SealedShapeDispatchDemo() stdout <- Stdout() processor <- ShapeProcessor() stdout.println(processor.describe(Circle())) stdout.println(processor.describe(Square())) stdout.println(processor.describe(Triangle()))
Common mistakes
E07120 — The dispatcher entry and all handlers must agree on purity. If the entry is 'as pure dispatcher', every handler must also be 'as pure'. The compiler detects this as a method signature conflict. See ek9 -h E07120 for details.
Incorrect:
describe() as pure dispatcher -> shape as Shape describe() -> shape as Circle
Correct:
describe() as dispatcher -> shape as Shape
Other ways to ask this
- Write a dispatcher with handlers for every permitted type of a sealed trait.
- Implement exhaustive dispatch over a sealed Shape hierarchy.
- Show me how to use a dispatcher with 'allow only' to enforce exhaustive handling.
- Build a ShapeProcessor that dispatches differently for Circle, Square and Triangle.
Coming from another language?
Java: visitor pattern with accept(visitor) on each subclass. Scala: pattern matching on sealed trait. Kotlin: when expression on sealed class. Rust: match on enum variants. EK9: dispatcher method with one handler per permitted type — no boilerplate, type-checked, exhaustiveness verified.
Keywords: dispatcher, allow only, trait, exhaustive, sealed, dispatch, handler, runtime