What is method shadowing and how does EK9 handle it?

← Type Hierarchy Constraints · Ref: Q606

'Shadowing' usually means a child class declaring a method that silently replaces or hides a parent method. EK9 splits this into three cases and decides each one by the SIGNATURE (name plus parameter types):

1. SAME NAME, SAME SIGNATURE, NO 'override' - E05120
The child method would replace the parent's, but without saying so. EK9 rejects it with E05120: an accidental override is not allowed. Add 'override' if replacement is what you mean, or rename the method if it is not.

2. SAME NAME, SAME SIGNATURE, WITH 'override' - a proper override
Calls through a parent-typed reference reach the child's version: the object decides which method runs.

3. SAME NAME, DIFFERENT SIGNATURE - an overload, which is legal
A child may add format(text, prefix) beside the inherited format(text). Both are available on the child; a call picks the one whose parameters match. It is NOT an override, so marking it 'override' is E05110 (it does not override anything).

WHY THIS MATTERS

In Java, forgetting @Override means a typo in a parameter type silently creates a new method, and a matching signature without the annotation silently overrides. EK9 makes the intent explicit: an override must say 'override' (E05120 otherwise), and 'override' must really match a parent signature (E05110 otherwise).

WHAT TO DO

If replacing parent behaviour: use 'override' with the EXACT same parameter types. If adding behaviour: an overload with different parameters is fine, or use a distinct, descriptive name when the meaning differs.

See Q570 for override basics. See Q571 for missing override keyword. See Q572 for false override claims.

Example

defines module qa.typehierarchy.methodshadow

  defines class

    Formatter as open
      format() as pure
        -> text as String
        <- rtn as String: text

      describe() as pure
        <- rtn as String: "base formatter"

      default operator ?

    UpperFormatter extends Formatter
      //CORRECT: override with exact same signature
      override format() as pure
        -> text as String
        <- rtn as String: text.upperCase()

      override describe() as pure
        <- rtn as String: "upper formatter"

      //CORRECT: an overload - same name, different parameters, no 'override'
      format() as pure
        ->
          text as String
          prefix as String
        <- rtn as String: prefix + text.upperCase()

      //CORRECT: new method with a different name (no collision)
      formatWithPrefix() as pure
        -> text as String
        <- rtn as String: ">> " + text.upperCase()

      default operator ?

  defines function

    testProperOverride()
      base <- Formatter()
      upper <- UpperFormatter()

      require base.format("hello") == "hello"
      require upper.format("hello") == "HELLO"
      require upper.formatWithPrefix("hello") == ">> HELLO"
      require upper.format("hello", "# ") == "# HELLO"

      //Polymorphic: calling through parent type still dispatches correctly
      formatters <- List() of Formatter
      formatters += Formatter()
      formatters += UpperFormatter()

      for formatter in formatters
        result <- formatter.format("test")
        require result?

Common mistakes

E05120 — UpperFormatter.format has the same signature as Formatter.format, so it replaces it and must say so with 'override'. Without it, the compiler reports E05120. See ek9 -h E05120 for details.

Incorrect:

format() as pure

Correct:

override format() as pure

E05110 — Adding override to formatWithPrefix would be a false claim since Formatter has no method named formatWithPrefix. The compiler rejects override when no parent method matches. See ek9 -h E05110 for details.

Incorrect:

override formatWithPrefix() as pure

Correct:

formatWithPrefix() as pure
Other ways to ask this
  • What is E05120 in EK9?
  • How does EK9 detect method shadowing?
  • Can a child class have a method with the same name but a different signature in EK9?

Coming from another language?

Java: a matching signature overrides with or without @Override; a different signature is an overload. C++: hiding is allowed by default, 'override' keyword optional. C#: 'new' keyword can explicitly shadow (EK9 has no such keyword). Python: no override concept, last definition wins. Kotlin: 'override' required, similar to EK9. Swift: 'override' required, similar to EK9. EK9: a same-signature method without 'override' is E05120; 'override' on a different signature is E05110; a different signature without 'override' is a legal overload.

Keywords: type, collision, overload, parent, circular, abstract, function, virtual, hierarchy, shadowing, child, inherit, E05120, signature, name, shadow, substitution, override, open