E08271: a 'register' statement constructs what it registers - call a constructor of the component or service (and of each aspect), not a function, method or delegate
What went wrong
A 'register' statement must CONSTRUCT what it registers. The application builds each registered value itself, in the order the 'register' statements are written, before any program runs - so the registered expression is a constructor call of the component (with 'as') or the service (without 'as'). The same holds for each aspect in 'with aspect of'.
These are rejected: the result of a function ('register makeOther() as Other'), a call through a function delegate, a service made by a function, a dynamic function, and an aspect made by a function ('with aspect of makeTracing()').
A factory can reach an injection that is not registered yet, and whatever it returned would be stored as the component - the application could not check its wiring.
Worked examples
Compilable examples demonstrating this error and the correct fix:
- ek9 -q 326 (What is the EK9 equivalent of Spring @Bean and @Configuration?)
- ek9 -q 228 (Why does registration order matter in EK9 applications?)
The [EXAMPLE] section below shows a component registered from a factory function, then the factory's work moved into the component's constructor (which injects what it needs) and the component registered by a constructor call, after what it injects.
How to fix it
- Register a constructor call: 'register Impl() as AbstractType', or 'register SomeService()'.
- Move the factory's work into the component's constructor; anything it needs is injected there, and must be registered before it (E08200).
- For an aspect, construct it: 'with aspect of Tracing()', where Tracing extends Aspect.
Common causes
- Spring @Bean / Guice @Provides habit: a factory method that builds the component
- Wanting to choose an implementation at runtime - define a separate application per configuration
- Passing a delegate variable that holds a factory function
See also
- E08271: a registration that is not a constructor call (this error)
- E50020: the constructed type is not a component (with 'as') or not a service (without 'as')
- E50030: the constructed component is not the 'as' type, or an aspect is not an Aspect
- E08200: a registration injects something registered after it
- E08210: an injection reachable from a program is not registered
Examples
Every example is compiled by the EK9 compiler: the first fails exactly as captioned, the others fix it.
Fails with E08271: a 'register' statement constructs what it registers - call a constructor of the component or service (and of each aspect), not a function, method or delegate
#!ek9 defines module error.e08271.bad defines function makeOther() <- rtn as Other: Labelled() defines component Svc as abstract name() as abstract <- rtn as String? SvcImpl is Svc override name() <- rtn as String: "service" Other as abstract tag() as abstract <- rtn as String? Labelled is Other label as String? Labelled() svc as Svc! label: svc.name() override tag() <- rtn as String: label default operator ? defines application App register SvcImpl() as Svc register makeOther() as Other
Fixed: Register a constructor call of the component
#!ek9 defines module error.e08271.good defines component Svc as abstract name() as abstract <- rtn as String? SvcImpl is Svc override name() <- rtn as String: "service" Other as abstract tag() as abstract <- rtn as String? Labelled is Other label as String? Labelled() svc as Svc! label: svc.name() override tag() <- rtn as String: label default operator ? defines application App register SvcImpl() as Svc register Labelled() as Other