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