How do I implement a trait for my class?

← Classes and OOP · Ref: Q108

Note: override applies to both methods and operators (e.g., override operator ? as pure, override operator $ as pure).

In EK9, implement a trait using 'with trait of' on the class declaration. You must override all abstract methods from the trait. You can optionally override default methods.

SYNTAX

Use 'with trait of TraitName' after the class name:

  EmailSender with trait of Sender
    override send()
      -> message as String
      <- rtn as Boolean: true

IMPLEMENTING REQUIRED METHODS

Abstract trait methods must be overridden in the class:

  defines trait
    Sender
      send() as abstract
        -> message as String
        <- rtn as Boolean?

The class must provide 'override send()' with a body.

OVERRIDING DEFAULT METHODS

Methods with bodies in the trait are optional to override:

  defines trait
    Sender
      retry()
        <- rtn as Integer: 3

The class inherits retry() returning 3, or can override it.

TRAIT HIERARCHIES

Traits can extend other traits:

  ReliableSender with trait of Sender
    acknowledge() as abstract
      <- rtn as Boolean?

A class implementing ReliableSender must implement both send() and acknowledge().

See Q106 for trait basics. See Q107 for multiple traits. See Q93 for class basics. See Q115 for dynamic classes implementing traits.

Example

defines module qa.oop.implementtrait

  defines trait

    Sender
      send() as abstract
        -> message as String
        <- rtn as Boolean?

      retry() as pure
        <- rtn as Integer: 3

    ReliableSender with trait of Sender
      acknowledge() as abstract
        <- rtn as Boolean?

  defines class

    EmailSender with trait of Sender
      override send()
        -> message as String
        <- rtn as Boolean: true

      default operator ?

    SmtpSender with trait of ReliableSender
      override send()
        -> message as String
        <- rtn as Boolean: true

      override acknowledge()
        <- rtn as Boolean: true

      override retry() as pure
        <- rtn as Integer: 5

      default operator ?

  defines program

    ImplementTraitDemo()
      stdout <- Stdout()

      // === BASIC TRAIT IMPLEMENTATION ===

      email <- EmailSender()
      stdout.println(`Send: ${email.send("Hello")}`)
      stdout.println(`Default retry: ${email.retry()}`)

      // === TRAIT HIERARCHY ===

      smtp <- SmtpSender()
      stdout.println(`Send: ${smtp.send("Hello")}`)
      stdout.println(`Acknowledge: ${smtp.acknowledge()}`)
      stdout.println(`Override retry: ${smtp.retry()}`)

Common mistakes

E05120 — When implementing an abstract trait method, the 'override' keyword is mandatory. EmailSender must use 'override send()' to implement Sender's abstract send method. See ek9 -h E05120 for details.

Incorrect:

send()

Correct:

override send()

E05120 — When overriding a default trait method, the 'override' keyword is required. SmtpSender overrides Sender's default retry() so it must use 'override'. See ek9 -h E05120 for details.

Incorrect:

retry() as pure

Correct:

override retry() as pure

E07130 — SmtpSender implements ReliableSender which extends Sender. The abstract send() from Sender must be overridden. Omitting it triggers E07130 — not declared abstract but still has abstract methods. See ek9 -h E07130 for details.

Incorrect:

//send not implemented

      override acknowledge()

Correct:

override send()
        -> message as String
        <- rtn as Boolean: true

      override acknowledge()

E05110 — The 'override' keyword claims a method exists in the hierarchy, but 'snd' does not match any method in Sender. This catches typos and refactoring errors — if a trait method is renamed, all implementors are flagged. See ek9 -h E05110 for details.

Incorrect:

override snd()
        -> message as String
        <- rtn as Boolean: true

Correct:

override send()
        -> message as String
        <- rtn as Boolean: true
Other ways to ask this
  • What is the syntax for implementing a trait in EK9?
  • How do I add trait methods to a class in EK9?
  • How do I override trait default methods?

Coming from another language?

Java: 'class MyClass implements MyInterface', must implement all abstract methods, @Override annotation optional but recommended. Python: class MyClass(ABC) with @abstractmethod, no enforcement until instantiation. Rust: 'impl Trait for Type' block with all required methods. Go: implicit implementation, no keyword needed, just match method signatures. Kotlin: 'class MyClass : MyInterface', override keyword required. EK9: 'ClassName with trait of TraitName', override keyword required for all overridden methods, compiler enforces abstract method implementation.

Keywords: virtual, override, sender, class, trait, default, hierarchy, syntax, object-oriented, required, open, method, abstract, implement