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 abstract
      <- rtn as Boolean?
    protocol() as pure
      <- rtn as String: "generic"

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"

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

E07110 — You cannot combine 'as abstract' and 'as open'. An abstract class is implicitly open — 'as abstract' is sufficient on its own. See ek9 -h E07110 for details.

Incorrect:

Database as abstract as open

Correct:

Database as 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: implicitly open, Database, inheritance, abstract class, extends, as abstract