E08170: an injected component is never assigned, not even with ':=?' - for a fallback, assign to a new variable ('chosen <- supplied' then 'chosen :=? injected')

Category: E08xxx Pre-IR checks (flow analysis) · Reported in phase: FULL_RESOLUTION · Classification: REASSIGNMENT_OF_INJECTED_COMPONENT · All error codes

What went wrong

You're assigning to an INJECTED component variable ('name as T!'). An injected variable is never assigned - not with ':=', and not with ':=?' either. The application sets it, and the compiler proves every injection a program reaches is registered (E08210, E08220), so it is always set: ':=?' would never apply.

Worked examples

Compilable examples demonstrating this error and the correct fix:

  • ek9 -q 669 (Why can't I reassign an injected component variable?)

Rationale

Injection dependencies should remain stable after initialization. The application wiring manages the component lifecycle — manual reassignment would break the contract between application wiring and injection sites.

How to fix it

  1. Remove the assignment and use the injected component as it is.
  2. If you need a fallback, assign to a NEW variable and fall back to the injected one (the [EXAMPLE] section below: 'chosen' takes the supplied Timekeeper, then the injected one only if it is unset)
  3. If the component should be replaceable, do not inject it: pass it as a parameter or hold it in an ordinary variable or property.

Common causes

  • Trying to change an injected dependency at runtime
  • Using ':=?' on the injected variable as an "optional injection" fallback - it is never unset
  • Habit from Spring/Guice, where an injected field can be reassigned or left null

See also

  • E08170: injected variable reassignment (this error)
  • E08266: checking that an injected component is set
  • E08180: property not initialized or injected

Examples

Every example is compiled by the EK9 compiler: the first fails exactly as captioned, the others fix it.

Fails with E08170: an injected component is never assigned, not even with ':=?' - for a fallback, assign to a new variable ('chosen <- supplied' then 'chosen :=? injected')

#!ek9
defines module error.e08170.bad

  defines function

    report()
      <- rtn as String?
      timekeeper as Timekeeper!
      timekeeper :=? NoonKeeper()
      rtn: timekeeper.now()

  defines component

    Timekeeper as abstract
      now() as pure abstract
        <- rtn as String?

    NoonKeeper is Timekeeper
      override now() as pure
        <- rtn as String: "noon"

Fixed: For a fallback, assign to a new variable

#!ek9
defines module error.e08170.good

  defines function

    report()
      -> supplied as Timekeeper
      <- rtn as String?
      timekeeper as Timekeeper!
      chosen <- supplied
      chosen :=? timekeeper
      rtn: chosen.now()

  defines component

    Timekeeper as abstract
      now() as pure abstract
        <- rtn as String?

Questions and answers

These Q&A entries show E08170 and its fix: