Why must component fields be initialized or injected?

← DI Validation · Ref: Q670

Every component field must either have an initial value or be marked for injection with '!' (E08180). Uninitialized, non-injected fields leave the object in an undefined state.

FIELD INITIALIZATION

  defines component
    MyComponent
      counter as Integer: 0             // Initialized
      items as List of String: List() of String  // Initialized

FIELD INJECTION

  defines component
    MyComponent
      repository as Repository!          // Injected by container

BOTH IN SAME COMPONENT

  defines component
    OrderService
      repository as Repository!          // Injected
      retryLimit as Integer: 3           // Initialized

See Q667 for abstract injection. See Q669 for reassignment. See Q671 for circular dependencies.

Example

defines module qa.divalidation.fieldinit

  defines component

    <?-
      Abstract message formatter contract.
    -?>
    MessageFormatter as abstract

      formatText() as abstract
        -> rawText as String
        <- formatted as String?

      default operator ?

    <?-
      Uppercase formatter implementation.
    -?>
    UpperCaseFormatter extends MessageFormatter

      override formatText()
        -> rawText as String
        <- formatted as String: ""

        formatted: rawText.upperCase()

      default operator ?

  defines application

    NotificationApp
      register UpperCaseFormatter() as MessageFormatter

  defines program

    FieldInitDemo() with application of NotificationApp
      stdout <- Stdout()

      formatter as MessageFormatter!
      result <- formatter.formatText("hello world")
      stdout.println(`Formatted: ${result}`)

Common mistakes

E08180 — Every component field must either be initialized with a value or marked for injection with '!'. A field declared without initialization and without the injection suffix leaves the object in an undefined state. Use '!' for DI-managed fields or provide an initial value. See ek9 -h E08180 for details.

Incorrect:

formatter as MessageFormatter

Correct:

formatter as MessageFormatter!
Other ways to ask this
  • What is E08180 property not initialized?
  • How do I initialize fields in components?
  • What is the difference between field initialization and injection?

Coming from another language?

Java: fields can be null (NPE risk). Python: fields set in __init__. Go: zero values for all fields. Rust: all fields must be initialized. EK9: fields must be initialized or injected, no uninitialized state allowed.

Keywords: property, field, component, inject, DI, registration, initialization, E08180, injection, validate