What are the access modifier rules for method overrides?

← Override Mechanics · Ref: Q573

Note: override applies to both methods and operators (e.g., override operator ? as pure, override operator $ as pure).

When overriding a method, the override must use EXACTLY the parent's access modifier. You can neither narrow it nor widen it. The compiler reports E05130 for any difference.

THE RULE

Public parent method requires a public override. Protected parent method requires a protected override. Private methods cannot be overridden (not visible to children).

THE ERROR: E05130

E05130 ('methods with same signature have different access modifiers') fires when an override's access modifier differs from the parent's in either direction - a public parent method made protected in the child, or a protected parent method made public.

WHY THIS RULE

One method, one contract: the override is the same method as the parent's, so it keeps the same visibility. Narrowing would break code that calls the parent method polymorphically; widening would quietly publish what the parent chose to keep inside the hierarchy.

DEFAULT ACCESS

In EK9, methods without an explicit modifier are public. Use 'private' or 'protected' to restrict access.

NO PRIVATE OVERRIDE

Private methods are not inherited and cannot be overridden. They are invisible to child classes, and writing 'override private' is E07010 (remove 'override' when using 'private').

See Q570 for override basics. See Q572 for false override claims. See Q95 for field visibility.

Example

defines module qa.override.accessmodifiers

  defines constant

    MIN_ENHANCED_LENGTH <- 2

  defines class

    Service as open
      //Public method (default)
      process() as pure
        -> request as String
        <- rtn as String: "processed: " + request

      //Protected method
      protected validate() as pure
        -> input as String
        <- rtn as Boolean: length input > 0

      default operator ?

    //Correct: public override of public method
    EnhancedService extends Service
      override process() as pure
        -> request as String
        <- rtn as String: "enhanced: " + request

      //Correct: keep it protected - an override uses exactly the parent's
      //access modifier; widening it to public is E05130 as well
      override protected validate() as pure
        -> input as String
        <- rtn as Boolean: length input > MIN_ENHANCED_LENGTH

      default operator ?

  defines program

    AccessModifierRulesDemo()
      stdout <- Stdout()

      svc <- EnhancedService()
      stdout.println(svc.process("hello"))

Common mistakes

E07010 — A private method cannot be an override: private methods are not inherited, so 'override' and 'private' together are rejected. Keep the parent's access modifier (public here). See ek9 -h E07010 for details.

Incorrect:

override private process() as pure

Correct:

override process() as pure

E07010 — 'override private' is rejected outright: a private method is never an override. The override of a protected parent method must itself be protected. See ek9 -h E07010 for details.

Incorrect:

override private validate() as pure

Correct:

override protected validate() as pure
Other ways to ask this
  • What is E05130 method access modifiers differ?
  • Can I change the visibility of an overridden method?
  • Can I make an override more or less restrictive?

Coming from another language?

Java: an override may widen visibility (protected to public) but not reduce it. Kotlin and C#: similar, with C# requiring the same access for overrides. EK9: stricter than Java - the override's access modifier must match the parent's exactly (E05130 for narrowing or widening).

Keywords: restrictive, modifier, protected, override, public, virtual, access, inherit, visibility, private, abstract, function, open, E05130