Create me a Database abstract class that PostgresDatabase can extend, showing that 'as abstract' makes the class implicitly open to extension.
← Classes and OOP · Ref: Q1251
An ABSTRACT class in EK9 is IMPLICITLY open. You do NOT need 'as open' on an abstract class — the 'as abstract' modifier already allows extension because an abstract class is meaningless without a concrete subclass.
ABSTRACT PARENT
Database as abstract connectionString as String: String()
default Database()
connect() as pure abstract <- rtn as Boolean?
protocol() as pure <- rtn as String: "generic"
default operator ?
An abstract class can have BOTH abstract methods (no body, subclass MUST implement) AND concrete methods (default behaviour subclass can override).
CONCRETE CHILD
PostgresDatabase extends Database default PostgresDatabase()
override connect() as pure <- rtn as Boolean: true
override protocol() as pure <- rtn as String: "postgres"
default operator ?
The child must override every abstract method. Concrete methods are optional to override.
TWO WAYS TO MAKE A CLASS EXTENSIBLE
- 'as open' — concrete class, has a working default, subclasses are optional
- 'as abstract' — incomplete class, MUST be subclassed, implicitly open
You CANNOT write 'as abstract as open' or 'as open as abstract' — these are mutually exclusive syntactically.
See Q1250 for 'as open' on concrete classes. See Q1043 for diagnosing E05030. See Q784 for closed-by-default rationale.
Example
defines module qa.classesandoop.abstractdatabase defines class Database as abstract connectionString as String: String() default Database() connect() as pure abstract <- rtn as Boolean? protocol() as pure <- rtn as String: "generic" default operator ? PostgresDatabase extends Database default PostgresDatabase() override connect() as pure <- rtn as Boolean: true override protocol() as pure <- rtn as String: "postgres" default operator ? defines program AbstractDatabaseDemo() stdout <- Stdout() db <- PostgresDatabase() stdout.println(`Protocol: ${db.protocol()}`) stdout.println(`Connected: ${db.connect()}`)
Common mistakes
E05160 — An override cannot be 'pure' when the abstract method it implements is not 'pure'. Declare the abstract method 'as pure abstract' so every implementation can be pure. See ek9 -h E05160 for details.
Incorrect:
connect() as abstract
Correct:
connect() as pure abstract
Other ways to ask this
- How does 'as abstract' relate to E05030 and the open/closed rule?
- Show me that an abstract class does not need 'as open' to be extensible.
- Write a Database abstract parent and a PostgresDatabase concrete child.
- Make a class extensible by marking it as abstract instead of as open.
Coming from another language?
Java: abstract classes can be extended regardless of 'final'. Kotlin: abstract implies open. Scala: abstract implies extensible. C#: abstract classes are implicitly inheritable. Python: ABC classes work similarly. EK9: 'as abstract' makes the class implicitly open — no need for both modifiers.
Keywords: inheritance, Database, implicitly open, as abstract, extends, abstract class