Why can I only inject components, not classes, in EK9?

← Dependency Injection · Ref: Q957

EK9 dependency injection (the '!' suffix) only works with abstract component types. Classes, records, functions, and traits cannot be injected. E08160 is raised when you attempt to inject a non-component type.

WHY COMPONENTS ONLY

Components are EK9's managed service layer. The DI container knows how to create, wire, and lifecycle-manage components. Classes are user-constructed objects — the container has no way to manage their lifecycle.

INJECTABLE (component genus)

  defines component
    Logger as abstract
      log() as abstract -> message as String

NOT INJECTABLE (E08160)

  defines class — user-managed objects
  defines record — data-only aggregates
  defines trait — interface contracts
  defines function — callable units

CORRECT PATTERN

  notifier as NotificationService!    // OK: NotificationService is abstract component

INCORRECT PATTERN

  helper as HelperClass!              // E08160: HelperClass is a class, not a component

See Q668 for injectable contexts. See Q111 for component basics. See Q672 for program-application linking.

Example

defines module qa.di.componentinjectioncontext

  defines class

    <?-
      A regular classnot a component. Cannot be injected.
    -?>
    HelperClass
      label <- "helper"

      default HelperClass()

      getLabel()
        <- rtn as String: label

      default operator ?

  defines component

    <?-
      Abstract component — can be injected via DI.
    -?>
    NotificationService as abstract

      sendNotification() as abstract
        -> recipient as String

      default operator ?

    <?-
      Concrete component implementing the abstract service.
    -?>
    EmailNotifier extends NotificationService

      override sendNotification()
        -> recipient as String
        stdout <- Stdout()
        stdout.println(`Email to ${recipient}`)

      default operator ?

  defines application

    NotifyApp
      register EmailNotifier() as NotificationService

  defines program

    ComponentInjectionDemo() with application of NotifyApp
      stdout <- Stdout()

      notifier as NotificationService!
      notifier.sendNotification("demo-user")

      stdout.println("Component injection works for abstract components")

Common mistakes

E08160 — Only abstract component types can be injected with '!'. Classes are not managed by the DI container. Use a component for injectable dependencies. See ek9 -h E08160 for details.

Incorrect:

      notifier as HelperClass!

Correct:

      notifier as NotificationService!
Other ways to ask this
  • What triggers E08160 COMPONENT_INJECTION_NOT_POSSIBLE?
  • Why does injection with ! fail for class types?
  • What types support dependency injection in EK9?

Coming from another language?

Java Spring: @Autowired works on any managed bean. Python: inject anywhere. Go: manual wiring. Rust: no DI framework. EK9: injection limited to abstract components for architectural clarity, E08160 if wrong construct genus.

Keywords: service, genus, component, class, construct, DI, managed, injection, E08160, abstract