What happens if I try to extend or override in a closed type?
← Override Mechanics · Ref: Q574
EK9 types are closed by default. You can only extend a class that is declared 'as open' or 'as abstract'. Attempting to extend a closed class produces E05030. Since you cannot extend a closed class, you cannot override its methods.
CLOSED BY DEFAULT
Every class without 'as open' or 'as abstract' is closed:
FinalProcessor
process() ...
No class can extend FinalProcessor.
OPEN FOR EXTENSION
Add 'as open' to allow extension:
ProcessorBase as open process() ...
Now children can extend and override.
ABSTRACT IS ALWAYS OPEN
Abstract classes must be extended (they are incomplete), so they are always open:
AbstractProcessor as abstract process() as abstract ...
WHY CLOSED BY DEFAULT
Prevents fragile base class problems. Reduces the surface area for bugs. Forces deliberate design for extension. Follows modern language trends (Kotlin, Swift).
See Q101 for why types are closed by default. See Q102 for 'as open'. See Q103 for abstract classes. See Q570 for override basics.
Example
defines module qa.override.closedtype defines constant MIN_STRICT_LENGTH <- 3 defines class //Closed class: cannot be extended ClosedValidator validate() as pure -> input as String <- rtn as Boolean: length input > 0 default operator ? //Open class: can be extended and methods overridden OpenValidator as open validate() as pure -> input as String <- rtn as Boolean: length input > 0 default operator ? //Extending the open class is allowed StrictValidator extends OpenValidator override validate() as pure -> input as String <- rtn as Boolean: length input > MIN_STRICT_LENGTH default operator ? //Abstract class: always open AbstractValidator as abstract check() as pure abstract -> input as String <- rtn as Boolean? default operator ? //Must extend abstract to use it EmailValidator extends AbstractValidator override check() as pure -> input as String <- rtn as Boolean: input contains "@" default operator ? defines program ClosedTypeDemo() stdout <- Stdout() //Closed class used directly closed <- ClosedValidator() stdout.println(`Closed: ${ closed.validate("hi")}`) //Open class hierarchy strict <- StrictValidator() stdout.println(`Strict: ${strict.validate("hi")}`) stdout.println(`Strict: ${strict.validate("hello")}`) //Abstract class hierarchy emailCheck <- EmailValidator() stdout.println(`Email: ${emailCheck.check("user@host")}`) stdout.println(`Email: ${emailCheck.check("invalid")}`)
Common mistakes
E05030 — ClosedValidator is not declared as open, so no class can extend it. EK9 types are closed by default. See ek9 -h E05030 for details.
Incorrect:
StrictValidator extends ClosedValidator
Correct:
StrictValidator extends OpenValidator
E05120 — When overriding the validate method from OpenValidator, the override keyword is mandatory. Omitting it causes a shadowing error. See ek9 -h E05120 for details.
Incorrect:
validate() as pure
Correct:
override validate() as pure
Other ways to ask this
- What is E05100 override inappropriate for closed types?
- Can I override methods if the parent is not 'as open'?
- Why can't I extend a closed class?
Coming from another language?
Java: all classes open by default, 'final' to close. Python: all classes open. Kotlin: classes closed by default, 'open' to allow extension. Swift: classes closed by default, 'open' to allow overriding. EK9: closed by default, 'as open' to allow extension.
Keywords: migrate, override, inherit, default, closed, final, E05030, extend, open, virtual, abstract