Why can't I register two implementations for the same abstract type?
← DI Validation · Ref: Q674
Each abstract component type can have exactly ONE concrete registration per application (E08230). Duplicate registrations create ambiguity in injection resolution.
WHY ONE REGISTRATION ONLY
When a program injects 'service as Logger!', the compiler must resolve exactly one concrete implementation. Two registrations for Logger would make resolution ambiguous.
DIFFERENT APPLICATIONS FOR DIFFERENT WIRING
Instead of duplicate registrations, use different applications:
defines application ProdApp register FileLogger() as Logger defines application TestApp register MockLogger() as Logger
Each application has one Logger binding.
See Q672 for program-application linking. See Q673 for missing registration. See Q671 for circular dependencies.
Example
defines module qa.divalidation.duplicatereg defines component <?- Abstract email service contract. -?> EmailService as abstract sendEmail() as abstract -> recipient as String default operator ? <?- SMTP implementation for production. -?> SmtpEmailService extends EmailService override sendEmail() -> recipient as String stdout <- Stdout() stdout.println(`SMTP email to ${recipient}`) default operator ? <?- Mock implementation for testing. -?> MockEmailService extends EmailService override sendEmail() -> recipient as String stdout <- Stdout() stdout.println(`Mock email to ${recipient}`) default operator ? defines application <?- Production application: ONE registration for EmailService. Each abstract type has exactly one concrete binding. -?> ProductionConfig register SmtpEmailService() as EmailService <?- Test application: different implementation, same abstract type. Use separate applications for different wiring configurations. -?> TestConfig register MockEmailService() as EmailService defines program DuplicateRegistrationDemo() with application of ProductionConfig stdout <- Stdout() emailService as EmailService! emailService.sendEmail("user@example.com") stdout.println("One abstract type = one registration per application") stdout.println("Use different applications for different implementations")
Common mistakes
E50010 — Each abstract component type can have exactly one concrete registration per application. Registering two implementations for EmailService in the same application creates ambiguity when the compiler tries to resolve injection points. Use separate applications for different wiring configurations. See ek9 -h E50010 for details.
Incorrect:
BrokenConfig
register SmtpEmailService() as EmailService
register MockEmailService() as EmailService
Correct:
ProductionConfig
register SmtpEmailService() as EmailService
Other ways to ask this
- What is E08230 duplicate registration?
- How do I handle multiple implementations of one interface?
- Can I register the same abstract type twice?
Coming from another language?
Java: Spring requires @Primary or @Qualifier for multiple beans. Python: manual selection. Go: manual wiring. Rust: no DI framework. EK9: one registration per abstract type per application, use different applications for different configurations.
Keywords: application, duplicate, registration, inject, DI, component, validate, E08230, ambiguous