E08200: component used before registration in application block

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

What went wrong

In the application block, a component is referenced before it has been registered. EK9 processes registrations sequentially, so a component must be registered before any component that depends on it.

An injection ('x as T!') loads T from the application when it runs, so the order covers everything that runs while a registration is made, not only the registered type's own injected properties: its constructor and property initialisers, the functions, methods and classes they call or construct, its aspects' constructors, and the calls in its arguments. An injection declared in the application body itself is loaded where it is written, so it must come after 'register ... as T'.

Components on a circular injection chain are not reported here: no order of registrations could satisfy them, so the chain is E08190 instead. A component outside the cycle that uses one of its members too early is still this error.

Worked examples

Compilable examples demonstrating this error and the correct fix:

  • ek9 -q 228 (Why does registration order matter in EK9 applications?)
  • ek9 -q 326 (What is the EK9 equivalent of Spring @Bean and @Configura...)
  • ek9 -q 234 (What is the lifecycle of injected components in EK9?)
  • ek9 -q 325 (What is the EK9 equivalent of Spring @Component and @Serv...)
  • ek9 -q 327 (How does EK9 DI compare to Spring Boot auto-configuration?)

How to fix it

  1. Reorder registrations so dependencies come before dependents
  2. Components without dependencies should be registered first
  3. Think of it as layered: infrastructure -> domain -> application
  4. Move an application-body injection below the registration of its type

See also

  • E08200: ordering error (this error)
  • E08190: circular dependency
  • E08210: missing registration

Examples

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

Fails with E08200: component used before registration in application block

#!ek9
defines module error.e08200.bad

  defines component

    AbstractA as abstract
      doWorkA() as abstract
        <- rtn as Boolean?

      default operator ?

    AbstractB as abstract
      doWorkB() as abstract
        <- rtn as Boolean?

      default operator ?

    ComponentA is AbstractA

      override doWorkA()
        <- rtn as Boolean: true

      default operator ?

    ComponentB is AbstractB
      svcA as AbstractA!

      override doWorkB()
        <- rtn as Boolean: true

      default operator ?

  defines application

    orderingApp
      register ComponentB() as AbstractB
      register ComponentA() as AbstractA

Fixed: Register what is injected before what it is injected into

#!ek9
defines module error.e08200.good.fix

  defines component

    AbstractA as abstract
      doWorkA() as abstract
        <- rtn as Boolean?

      default operator ?

    AbstractB as abstract
      doWorkB() as abstract
        <- rtn as Boolean?

      default operator ?

    ComponentA is AbstractA

      override doWorkA()
        <- rtn as Boolean: true

      default operator ?

    ComponentB is AbstractB
      svcA as AbstractA!

      override doWorkB()
        <- rtn as Boolean: true

      default operator ?

  defines application

    orderingApp
      register ComponentA() as AbstractA
      register ComponentB() as AbstractB

Fixed: Register what a component needs before the component

#!ek9
defines module error.e08200.good

  defines component

    AbstractA as abstract
      doWorkA() as abstract
        <- rtn as Boolean?
      default operator ?

    AbstractB as abstract
      doWorkB() as abstract
        <- rtn as Boolean?
      default operator ?

    ComponentA is AbstractA
      override doWorkA()
        <- rtn as Boolean: true
      default operator ?

    ComponentB is AbstractB
      svcA as AbstractA!
      override doWorkB()
        <- rtn as Boolean: svcA.doWorkA()
      default operator ?

  defines application

    orderingApp
      register ComponentA() as AbstractA
      register ComponentB() as AbstractB

Questions and answers

These Q&A entries show E08200 and its fix: