Can a class implement multiple traits in EK9?

← Classes and OOP · Ref: Q107

Yes, in EK9, a class can implement multiple traits. When traits have conflicting method signatures, you must resolve the ambiguity by providing an explicit override.

MULTIPLE TRAIT IMPLEMENTATION

List traits separated by commas:

  Report with trait of Printable, Exportable

CONFLICT RESOLUTION

When two traits define the same method, override it in the class:

  override format()
    <- rtn as String: Printable.format()

You can choose which trait's default to call using 'TraitName.method()' syntax.

ALLOW ONLY RESTRICTIONS

Traits can restrict which classes may implement them:

  Response allow only JsonResponse, XmlResponse

Only the listed classes can use 'with trait of Response'.

AMBIGUOUS METHODS

The compiler detects when trait methods conflict and requires explicit resolution. This prevents silent bugs from accidental method shadowing.

See Q106 for trait basics. See Q108 for implementing traits step by step. See Q105 for dispatching with traits. See Q576 for class and trait override resolution.

Example

defines module qa.oop.multipletraits

  defines trait

    Serializable
      toText()
        <- rtn as String: "serialized"

      override operator ? as pure
        <- rtn as Boolean: true

    Loggable
      toText()
        <- rtn as String: "logged"

      logLevel()
        <- rtn as String: "INFO"

      override operator ? as pure
        <- rtn as Boolean: true

  defines class

    Event with trait of Serializable, Loggable
      message <- String()

      Event()
        -> message as String
        this.message: message

      override toText()
        <- rtn as String: message

      override operator ? as pure
        <- rtn as Boolean: message?

  defines program

    MultipleTraitsDemo()
      stdout <- Stdout()

      // === MULTIPLE TRAITS ===

      event <- Event("User logged in")

      // toText() resolved by explicit override
      stdout.println(`Text: ${event.toText()}`)

      // logLevel() from Loggable (no conflict)
      stdout.println(`Level: ${event.logLevel()}`)

      stdout.println(`IsSet: ${event?}`)

Common mistakes

E05120 — When both Serializable and Loggable define toText(), the implementing class Event must explicitly override it to resolve the conflict. Omitting 'override' triggers E05120. See ek9 -h E05120 for details.

Incorrect:

toText()

Correct:

override toText()

E05120 — The '?' operator is defined in both traits. Event must use 'override operator ?' to resolve the conflict and provide its own implementation. See ek9 -h E05120 for details.

Incorrect:

operator ? as pure

Correct:

override operator ? as pure

E06150 — When two traits define the same method (toText() in both Serializable and Loggable), the implementing class must provide an explicit override to resolve the conflict. Without it, the compiler cannot determine which trait's default to use. See ek9 -h E06150 for details.

Incorrect:

//toText conflict not resolved

Correct:

override toText()
        <- rtn as String: message
Other ways to ask this
  • How do I use multiple traits on one class in EK9?
  • How does EK9 handle trait conflicts?
  • What happens when two traits have the same method?

Coming from another language?

Java: class implements multiple interfaces, default method conflicts require override with InterfaceName.super.method(). Python: multiple inheritance with MRO (Method Resolution Order), diamond problem handled by C3 linearisation. Rust: multiple trait implementations, explicit disambiguation with <Type as Trait>::method(). Go: struct satisfies multiple interfaces implicitly, no conflict possible (no defaults). Kotlin: multiple interfaces, conflicts resolved with super<InterfaceName>.method(). EK9: multiple traits with 'with trait of A, B', conflicts resolved with 'TraitName.method()' syntax, 'allow only' restricts implementors.

Keywords: diamond, trait, override, conflict, open, virtual, multiple, implement, resolve, class, ambiguous, abstract, object-oriented, only, allow