What is the maximum class inheritance depth in EK9?

← Code Quality · Ref: Q729

EK9 limits inheritance depth to prevent fragile base class problems. The limits vary by construct type:
- Class: DIT 4 (max 5 classes in a chain)
- Record: DIT 2
- Trait: DIT 4
- Component: DIT 4
- Function: DIT 3

DIT (Depth of Inheritance Tree) counts ancestor levels. A base class has DIT=0, its child DIT=1, and so on.

WHY LIMIT INHERITANCE DEPTH

This is a DESIGN limit, not a technical one. Deep hierarchies cause:
1. Fragile base class problem: changes at the top cascade unpredictably through all descendants
2. Comprehension burden: understanding a class at DIT=6 requires reading 7 class definitions
3. Constructor complexity: super() chains grow error-prone with each level
4. Testing explosion: each level multiplies the number of state combinations to test

EK9 OFFERS BETTER ALTERNATIVES

Instead of deep inheritance, EK9 provides:
- Traits for shared behavior without hierarchy depth
- Composition (has-a) instead of inheritance (is-a)
- The 'by' delegation keyword for forwarding calls

THIS EXAMPLE

The hierarchy below has DIT=4 for the leaf class (exactly at the class limit). Adding one more intermediate level would trigger E11019.

See Q697 for inheritance depth overview. See Q611 for hierarchy validation. See Q602 for circular hierarchy detection.

Example

defines module qa.codequality.inheritanceboundary

  defines trait

    <?-
      Traits add behavior without increasing inheritance depth.
    -?>
    Describable
      describe() as pure
        <- rtn as String: "describable"

  defines class

    //DIT=0: abstract root
    Vehicle as abstract
      engineType() as pure abstract
        <- rtn as String?

      default operator ?

    //DIT=1: first concrete level
    TwoWheeler extends Vehicle as open
      wheelCount <- 2

      override engineType() as pure
        <- rtn as String: "two-wheeler"

      getWheelCount() as pure
        <- rtn as Integer: wheelCount

      default operator ?

    //DIT=2: specialization
    Motorcycle extends TwoWheeler as open
      displacement <- Integer()

      Motorcycle()
        -> displacement as Integer
        this.displacement: displacement

      getDisplacement() as pure
        <- rtn as Integer: displacement

      override engineType() as pure
        <- rtn as String: "motorcycle"

      default operator ?

    //DIT=3: further specialization
    SportsBike extends Motorcycle as open
      hasFairing <- Boolean()

      SportsBike()
        ->
          displacement as Integer
          hasFairing as Boolean
        super(displacement)
        this.hasFairing: hasFairing

      override engineType() as pure
        <- rtn as String: "sports"

      default operator ?

    //DIT=4: exactly at the class limit
    //Adding one more level here would trigger E11019
    RacingBike extends SportsBike
      raceCategory <- String()

      RacingBike()
        ->
          displacement as Integer
          raceCategory as String
        super(displacement: displacement, hasFairing: true)
        this.raceCategory: raceCategory

      getRaceCategory() as pure
        <- rtn as String: raceCategory

      override engineType() as pure
        <- rtn as String: `racing (${raceCategory})`

      default operator ?

  defines program

    InheritanceDepthBoundaryDemo()
      stdout <- Stdout()

      racer <- RacingBike(displacement: 600, raceCategory: "Supersport")
      stdout.println(racer.engineType())
      stdout.println(racer.getRaceCategory())
      stdout.println($racer.getDisplacement())
      stdout.println($racer.getWheelCount())

Common mistakes

E50060 — Adding another level to the inheritance chain pushes DIT from 4 to 5, exceeding the class limit of 4. Use traits or composition instead of deeper inheritance. See ek9 -h E50060 for details.

Incorrect:

    TrackBike extends SportsBike as open
      default operator ?

    RacingBike extends TrackBike

Correct:

    RacingBike extends SportsBike
Other ways to ask this
  • What triggers E11019 excessive inheritance depth?
  • How deep can class hierarchies be?
  • What is the DIT limit for classes?
  • What are the DIT thresholds for each EK9 construct type?

Coming from another language?

Java: no depth limit (only convention). Python: MRO handles deep chains but they are a smell. C++: no depth limit. Kotlin: no depth limit. Rust: no inheritance. Go: no inheritance (uses embedding). EK9: compile-time depth limit with different thresholds per construct type.

Keywords: quality, class, trait, limit, boundary, hierarchy, depth, clean-code, fragile, DIT, inheritance, base, E11019, composition