Why can't I add 'as pure' to an override when the parent method isn't pure?

← Purity Contracts · Ref: Q562

You cannot add 'as pure' to an override when the parent method is not pure. The compiler reports E05160.

WHY YOU CANNOT ADD PURE

Callers using the parent type expect the method MAY have side effects. If the child adds purity, code using a parent reference cannot rely on it because another child might not be pure. Purity is a contract from the top of the hierarchy, not something added partway down.

THE ERROR: E05160

If you mark an override 'as pure' but the parent method is not pure, the compiler reports E05160: the parent method is not pure so you cannot add purity.

CORRECT APPROACH

Option 1: Remove 'as pure' from the override. The child matches the parent contract.
Option 2: If you control the parent, make the parent method pure. Then all children must follow.

DESIGN PRINCIPLE

Purity flows DOWN the hierarchy, not UP. The root type decides whether the contract is pure. Children honour it; they cannot change it in either direction.

See Q561 for the reverse rule (must keep pure). See Q560 for pure method basics. See Q567 for purity through inheritance chains.

Example

defines module qa.purity.cannotaddpure

  defines class

    //Parent is NOT pure: children must match
    Logger as open
      logMessage()
        -> message as String
        <- formatted as String: "[LOG] " + message

      default operator ?

    //Correct: child does NOT add pure
    TimestampLogger extends Logger
      override logMessage()
        -> message as String
        <- formatted as String: "[LOG:TS] " + message

      default operator ?

    //Separate pure hierarchy: designed pure from the start
    Formatter as abstract
      format() as pure abstract
        -> text as String
        <- rtn as String?

      default operator ?

    UpperFormatter extends Formatter
      override format() as pure
        -> text as String
        <- rtn as String: text.upperCase()

      default operator ?

  defines program

    CannotAddPureDemo()
      stdout <- Stdout()

      //Non-pure hierarchy
      logger <- TimestampLogger()
      stdout.println(logger.logMessage("system started"))

      //Pure hierarchy (designed pure from the start)
      formatter <- UpperFormatter()
      stdout.println(formatter.format("hello"))

Common mistakes

E05160 — The parent Logger.logMessage is not pure. Adding as pure to the override is forbidden because purity flows down from the top of the hierarchy, not up. See ek9 -h E05160 for details.

Incorrect:

override logMessage() as pure

Correct:

override logMessage()

E05150 — The parent Formatter.format is declared pure abstract. Overriding without as pure would violate the purity contract. See ek9 -h E05150 for details.

Incorrect:

override format()

Correct:

override format() as pure
Other ways to ask this
  • What is E05160 SUPER_IS_NOT_PURE?
  • Can I make a child method pure if the parent is not?
  • Why does EK9 prevent adding purity in an override?

Coming from another language?

Java: no purity concept, no enforcement. Kotlin: no purity. Rust: no purity on trait methods. Go: no purity. EK9: purity is a hierarchical contract enforced by E05160 (cannot add) and E05150 (cannot remove).

Keywords: open, hierarchy, function, purity, override, parent, abstract, immutable, add, pure, contract, E05160, forbidden, side-effect, virtual