How does EK9 resolve the diamond problem with trait method conflicts?

← Type Hierarchy Constraints · Ref: Q680

When a class implements two traits that declare the same method name, EK9 detects the conflict and requires the class to provide an explicit override to resolve it.

DIAMOND DETECTION (E05220)

If TraitA declares process() and TraitB also declares process(), a class implementing both has a conflict. The compiler detects this and reports E05220 unless the class provides an override.

RESOLUTION VIA OVERRIDE (E05230)

The class must provide its own 'override' of the conflicting method. This removes ambiguity by giving the class full control over the method body. Without the override, the compiler cannot choose between the two trait implementations and reports E05230.

UNREACHABLE DISPATCH (E05210)

In dispatchers, a handler for a type that is not reachable from the base dispatch type is flagged with E05210. This ensures all dispatcher handlers can actually be invoked.

CORRECT PATTERN

  TraitA
    process() ...
  TraitB
    process() ...
  MyClass with trait of TraitA, TraitB
    override process() ...   // Resolves the conflict

See Q107 for multiple trait implementation. See Q579 for trait override chains. See Q611 for hierarchy validation summary.

Example

defines module qa.typehierarchy.diamondtrait

  defines trait

    <?-
      First trait: declares a process() method with default.
    -?>
    Auditable
      auditEntry() as pure
        <- rtn as String: "audited"

      formatRecord() as pure
        <- rtn as String: `[AUDIT] ${auditEntry()}`

    <?-
      Second trait: declares a formatRecord() method too.
      This creates a conflict for classes implementing both traits.
    -?>
    Printable
      printLabel() as pure
        <- rtn as String: "printable"

      formatRecord() as pure
        <- rtn as String: `[PRINT] ${printLabel()}`

  defines class

    <?-
      Class implementing both traits.
      Must override formatRecord() to resolve the diamond conflict.
    -?>
    DocumentRecord with trait of Auditable, Printable
      title <- String()

      DocumentRecord()
        -> title as String
        this.title: title

      override auditEntry() as pure
        <- rtn as String: title

      override printLabel() as pure
        <- rtn as String: title

      //Resolves the diamond: both Auditable and Printable have formatRecord()
      override formatRecord() as pure
        <- rtn as String: `[DOC] ${title}`

      default operator ?

    <?-
      Another class implementing only one trait: no conflict.
    -?>
    SimpleAudit with trait of Auditable
      action <- String()

      SimpleAudit()
        -> action as String
        this.action: action

      override auditEntry() as pure
        <- rtn as String: action

      default operator ?

  defines program

    DiamondTraitDemo()
      stdout <- Stdout()

      doc <- DocumentRecord("Invoice #42")
      stdout.println(doc.formatRecord())
      stdout.println(doc.auditEntry())
      stdout.println(doc.printLabel())

      simple <- SimpleAudit("login")
      stdout.println(simple.formatRecord())

Common mistakes

E50010 — UnrelatedTrait is not defined in this module. Adding an unresolved type to the trait list triggers E50010. See ek9 -h E50010 for details.

Incorrect:

DocumentRecord with trait of Auditable, Printable, UnrelatedTrait

Correct:

DocumentRecord with trait of Auditable, Printable

E06150 — When two traits provide conflicting method implementations and the implementing class does not override the method to resolve the ambiguity, E06150 is reported. The class must provide its own override. See ek9 -h E06150 for details.

Incorrect:

//formatRecord() not overridden, leaving the diamond conflict unresolved

Correct:

override formatRecord() as pure
        <- rtn as String: `[DOC] ${title}`
Other ways to ask this
  • What is E05210 dispatcher unreachable handler?
  • What is E05220 method conflict from multiple traits?
  • What is E05230 unresolved trait method conflict?
  • How do I resolve conflicting methods from two traits?

Coming from another language?

Java: interface default method conflict requires class override. Kotlin: must override and can use super<TraitName>.method(). Python: MRO determines which implementation wins. C++: virtual inheritance for diamond. Rust: explicit disambiguation with <Type as Trait>::method(). EK9: class must provide override for conflicting trait methods.

Keywords: function, virtual, inherit, E05220, E05230, abstract, conflict, hierarchy, resolution, circular, type, open, multiple, diamond, override, trait, E05210