Why can't I use 'by' delegation inside a trait?

← Classes and OOP · Ref: Q770

The 'by' keyword delegates trait method implementations to a field. This only works in CLASSES, not in traits. Traits define interfaces and optional default implementations — they cannot hold fields or delegate to other objects.

DELEGATION SYNTAX (CLASS ONLY)

  MyClass with trait of SomeTrait by myField

This tells the compiler: when SomeTrait methods are called on MyClass, forward them to myField.

WHY NOT IN TRAITS

Traits are stateless contracts. Delegation requires a concrete field to forward to — traits have no fields. Attempting 'by' in a trait is a design error caught at compile time.

THIS EXAMPLE

The Renderable and Loggable traits define contracts. The Formatter class delegates Renderable to its helper field using 'by'. This is the correct pattern — delegation in a class.

COMMON MISTAKE

Developers try to compose traits using 'by'. In EK9, traits compose through 'with trait of' (listing multiple traits) or 'extends' (trait hierarchy), never through delegation.

See Q78 for traits. See Q85 for composition. See Q93 for classes.

Example

defines module qa.classesandoop.traitdelegation

  defines trait

    Renderable
      render()
        <- rtn as String?

    Loggable
      log()
        <- rtn as String?

    Combined with trait of Renderable, Loggable

  defines class

    RenderHelper with trait of Renderable
      label <- String()

      RenderHelper()
        -> l as String
        label :=: l

      override render()
        <- rtn as String: label

      default operator ?

    Formatter with trait of Renderable by helper
      helper as Renderable?

      default private Formatter()

      Formatter()
        -> h as Renderable
        require h?
        helper: h

      default operator ?

  defines program

    ShowDelegation()
      stdout <- Stdout()
      helper <- RenderHelper("formatted output")
      doc <- Formatter(helper)
      if doc?
        stdout.println(doc.render())

Common mistakes

E07040 — Adding 'by renderer' to a trait definition attempts delegation inside a trait. Traits have no fields to delegate to — delegation only works in classes. Remove 'by renderer' or move the delegation to a class. See ek9 -h E07040 for details.

Incorrect:

    Combined with trait of Renderable by renderer, Loggable

Correct:

    Combined with trait of Renderable, Loggable
Other ways to ask this
  • What triggers E07040 trait by identifier not supported?
  • How does trait delegation with by work in EK9?
  • Where can I use the by keyword for delegation?

Coming from another language?

Java: no delegation keyword, manual forwarding methods required. Kotlin: 'by' keyword works on interfaces in class declarations only. Rust: no delegation, use Deref or manual forwarding. Go: struct embedding provides implicit delegation. C#: no delegation keyword. EK9: 'by' delegation in class declarations only, not in traits.

Keywords: class, delegate, field, forward, interface, delegation, composition, by, trait, E07040