Review this design. Should it use composition instead of inheritance?
← Code Quality · Ref: Q1045
In EK9, composition is generally preferred over inheritance. Types are closed by default — you must explicitly opt into extension with 'as open'.
WHEN INHERITANCE IS APPROPRIATE:
- True 'is-a' relationship (Circle is a Shape)
- Shared behaviour that varies by subtype (abstract methods)
- Small, stable hierarchies (2-3 levels max)
WHEN COMPOSITION IS BETTER:
- 'Has-a' relationship (Car has an Engine, not Car is an Engine)
- Combining capabilities from multiple sources (use traits)
- When the parent class might change (composition isolates you)
- When you need to swap implementations at runtime
EK9 COMPOSITION TOOLS:
- Traits for shared contracts: 'with trait of Printable'
- Delegation with 'by' keyword
- Records for pure data aggregation
- Components for DI-managed services
The compiler enforces max inheritance depth — if you hit the limit, it is a signal to refactor toward composition.
Example
defines module qa.codequality.reviewcomposition defines trait Describable describe() as pure <- rtn as String? defines class Engine horsePower as Integer: 0 Engine() -> horsePower as Integer this.horsePower :=: horsePower horsePower() as pure <- rtn as Integer: horsePower default operator //Composition: Car HAS an Engine (correct) Car with trait of Describable engine as Engine: Engine(0) modelName as String: String() Car() -> modelName as String engine as Engine this.modelName :=: modelName this.engine :=: engine override describe() as pure <- rtn as String: `${modelName} (${engine.horsePower()}hp)` default operator defines program CompositionDemo() stdout <- Stdout() engine <- Engine(250) car <- Car("Roadster", engine) stdout.println(car.describe())
Common mistakes
E05030 — Car is not an Engine — it has an Engine. Use composition (field) not inheritance (extends). Also, Engine must be 'as open' to extend.
Incorrect:
defines class Car extends Engine
Correct:
defines class Engine
Other ways to ask this
- Is inheritance the right choice here or should I use composition?
- Assess whether this class hierarchy is appropriate
- When should I use composition over inheritance in EK9?
Coming from another language?
EK9 encourages composition through closed types, traits, and delegation. Inheritance is available but not the default approach.
Keywords: trait, inheritance, composition, delegation, review, design