How do overrides work when a class implements a trait and extends a parent?
← Override Mechanics · Ref: Q576
A class can extend a parent AND implement traits. When the same method appears in both, the class must provide an override that satisfies both contracts.
BOTH SOURCES
If a parent class has method X and a trait also declares method X with the same signature, the child class must override it once. The single override satisfies both.
TRAIT-ONLY METHODS
Methods that exist only in the trait (not in the parent) are overridden with 'override' just like any other inherited method.
PARENT-ONLY METHODS
Methods that exist only in the parent are overridden with 'override' in the normal way.
PURITY MUST AGREE
The parent method and the trait method must agree on 'pure'. If one is pure and the other is not, the compiler raises E05290 ('parents disagree on pure') - no single override can honour both a pure and a non-pure contract, so fix the parents. When they agree, the override matches that shared purity: a pure parent requires a pure override (E05150), and a non-pure parent forbids marking the override pure (E05160).
See Q106 for trait basics. See Q107 for multiple traits. See Q570 for override basics. See Q578 for open, abstract, and override relationships.
Example
defines module qa.override.classandtrait defines trait Printable display() as pure abstract <- rtn as String? Sizeable size() as pure abstract <- rtn as Integer? defines class Container as open describe() as pure <- rtn as String: "container" default operator ? //Extends parent AND implements traits NamedContainer extends Container with trait of Printable, Sizeable containerName <- String() itemCount <- 0 NamedContainer() -> containerName as String itemCount as Integer this.containerName: containerName this.itemCount: itemCount //Override from parent class override describe() as pure <- rtn as String: "named container: " + containerName //Override from Printable trait override display() as pure <- rtn as String: `${containerName} (${itemCount} items)` //Override from Sizeable trait override size() as pure <- rtn as Integer: itemCount default operator ? defines program ClassAndTraitOverrideDemo() stdout <- Stdout() nc <- NamedContainer("toolbox", 15) //Using through parent type container <- nc stdout.println(container.describe()) //Using through trait types printable <- nc stdout.println(printable.display()) sizeable <- nc stdout.println(`Size: ${sizeable.size()}`)
Common mistakes
E05120 — When implementing a trait method, the override keyword is required. Omitting it on display from the Printable trait triggers shadowing detection. See ek9 -h E05120 for details.
Incorrect:
display() as pure
Correct:
override display() as pure
E05110 — Claiming override on a method name that does not exist in the parent class or any implemented trait is a false override claim. See ek9 -h E05110 for details.
Incorrect:
override render() as pure
Correct:
override describe() as pure
Other ways to ask this
- What happens when a method comes from both a parent class and a trait?
- How does EK9 resolve overrides from class and trait sources?
- Can I override methods from both parent and trait?
Coming from another language?
Java: class extends + interface implements, @Override for both. Kotlin: class extends + interface implements, override required. EK9: class extends + 'with trait of', override required for both sources.
Keywords: implement, contract, both, trait, inherit, override, satisfy, abstract, virtual, class, open