Can functions form multi-level inheritance chains?
← Function Extension · Ref: Q593
EK9 functions can form multi-level chains: an abstract function at the top, with concrete implementations at each level. However, only abstract functions can be extended. A concrete function cannot be further extended.
ABSTRACT FUNCTION EXTENSION
Abstract functions define contracts that concrete functions implement:
BaseOp as pure abstract -> x as Integer <- rtn as Integer? DoubleOp is BaseOp as pure -> x as Integer <- rtn as Integer: x + x
CONCRETE FUNCTIONS ARE CLOSED
Once a function provides an implementation (has a body), it cannot be extended further. Only abstract functions can be the base of a hierarchy.
MULTIPLE IMPLEMENTATIONS
An abstract function can have many direct implementations, creating a flat hierarchy with one abstract parent and multiple concrete children.
See Q588 for function extension basics. See Q589 for multiple implementations. See Q594 for extension rules. See Q595 for pure abstract function constraints.
Example
defines module qa.function.multilevelchain defines constant MIN_FILTER_LENGTH <- 3 defines function //Abstract function: base of hierarchy Filter as pure abstract -> input as String <- passes as Boolean? //Multiple direct implementations (flat hierarchy) NonEmptyFilter is Filter as pure -> input as String <- passes as Boolean: length input > 0 LongEnoughFilter is Filter as pure -> input as String <- passes as Boolean: length input > MIN_FILTER_LENGTH ContainsAtFilter is Filter as pure -> input as String <- passes as Boolean: input contains "@" defines program MultilevelFunctionChainDemo() stdout <- Stdout() //All implementations share the abstract type filters <- List() of Filter filters += NonEmptyFilter filters += LongEnoughFilter filters += ContainsAtFilter testValues <- ["", "hi", "hello", "user@host"] for testVal in testValues stdout.println(`Testing: "${testVal}"`) for filterFn in filters stdout.println(` Passes: ${filterFn(testVal)}`)
Common mistakes
E50001 — A pure function cannot call non-pure methods like stdout.println(). Pure functions must have no side effects. See ek9 -h E50001 for details.
Incorrect:
NonEmptyFilter is Filter as pure -> input as String <- passes as Boolean: length input > 0 stdout.println(input)
Correct:
NonEmptyFilter is Filter as pure -> input as String <- passes as Boolean: length input > 0
Other ways to ask this
- Can a concrete function be extended further?
- How deep can function hierarchies go?
- Can I have Abstract -> Middle -> Concrete function chains?
Coming from another language?
Java: functional interfaces are flat (one method). Kotlin: function types are structural. Rust: Fn traits have no hierarchy. EK9: abstract functions can have multiple concrete implementations, concrete functions are closed.
Keywords: extend, function, multi-level, extension, chain, concrete, closed, abstract, hierarchy