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 FROM EITHER SOURCE
If either the parent method or the trait method is pure, the override must be pure. The strictest contract wins.
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: satisfy, override, inherit, trait, both, contract, implement, open, class, virtual, abstract