What does EK9 error E50040 mean when I write an abstract method in a component and how do I fix it?
← Dependency Injection · Ref: Q1290
E50040 fires when a method is declared 'as abstract' inside a construct that has not itself been marked 'as abstract'. For components the error usually reads:
Error : E50040: 'log' on line 7 position 6: is abstract, but construct on line 6 is not marked as abstract, 'public Void <- log(message as String) as abstract': cannot be abstract
The rule is symmetric: a method can only be 'as abstract' if the enclosing class, trait or component is ALSO 'as abstract'. Otherwise the compiler rejects the declaration at phase 1.
THE TWO VALID FIXES
1. Mark the enclosing component as abstract (preferred when you want an extensible base component that subclasses override):
defines component
Logger as abstract log() as abstract -> message as String
LoggerImpl extends Logger override log() -> message as String stdout <- Stdout() stdout.println(`LOG: ${message}`)
2. Give the method a concrete implementation and drop 'as abstract' (preferred when the base component already has a sensible default that subclasses can override):
defines component
Logger
log()
-> message as String
// default implementation
stdout <- Stdout()
stdout.println(`LOG: ${message}`)
COMPONENTS IN EK9
Components are the dependency-injection unit: they are registered in an application with 'register ComponentType() as Interface' and injected into other components and programs via 'field as Type!'. A component can be abstract (base type for a hierarchy) or concrete (a directly-instantiable implementation). The standard pattern is: ONE abstract component with the interface methods, ONE (or more) concrete extending components with the actual implementations, and the 'register' clause nominates the concrete implementation for the abstract interface.
WHY NOT USE A TRAIT?
Traits are for mix-in behaviour across class hierarchies — they compose interfaces without being the DI unit themselves. Components are specifically for dependency injection. Use a trait when you want multiple classes to share a method surface; use an abstract component when you want an injectable interface with multiple implementations registered per environment (test vs production, for example).
See Q103 for abstract classes and methods. See Q111 for components. See Q677 for how abstract flows through three-level hierarchies.
Example
defines module qa.dependencyinjection.e50040fix defines component Logger as abstract log() as abstract -> message as String LoggerImpl extends Logger override log() -> message as String stdout <- Stdout() stdout.println(`LOG: ${message}`) UserService as abstract createUser() as abstract -> userName as String UserServiceImpl extends UserService logger as Logger! override createUser() -> userName as String logger.log(`Created user: ${userName}`) override operator ? as pure <- rtn as Boolean: logger? defines application MyApp register LoggerImpl() as Logger register UserServiceImpl() as UserService defines program E50040FixDemo() with application of MyApp service as UserService! service.createUser("Alice") service.createUser("Bob")
Common mistakes
E50040 — Declaring a method 'as abstract' inside 'defines component / Logger' without marking Logger itself 'as abstract' fires E50040. A method can only be abstract when its enclosing construct is also abstract. Add 'as abstract' to the component header to fix it, or drop 'as abstract' from the method and provide a concrete implementation.
Incorrect:
Logger
Correct:
Logger as abstract
Other ways to ask this
- I'm getting E50040 'cannot be abstract' on a method inside defines component — what's wrong?
- Why can't I write 'log() as abstract' inside my EK9 Logger component?
- How do I make an extensible Logger component in EK9 without E50040?
- The compiler says my abstract method's container is not abstract — how do I fix it?
Coming from another language?
Java interfaces with abstract methods: the interface itself is implicitly abstract. EK9 components: you must state 'as abstract' explicitly on the containing component if the component has abstract methods. There is no implicit abstractness — 'defines component \n Logger \n log() as abstract' is a specific error (E50040), not a lenient shortcut.
Keywords: Logger, component, E50040, abstract component, dependency injection, abstract method