Can dynamic functions extend abstract functions?
← Function Extension · Ref: Q590
Yes, dynamic functions can extend abstract functions. A dynamic function is created inline and implements the abstract function's contract, typically capturing values from the surrounding scope.
DYNAMIC FUNCTION SYNTAX
Create a dynamic function that extends an abstract:
defines function Formatter as pure abstract -> text as String <- rtn as String?
Then create an implementation inline:
upper <- () is Formatter as pure (rtn:=? text.upperCase())
CLOSURE CAPTURE
Dynamic functions capture values from their enclosing scope. The captured values become part of the function instance:
tag <- "LOG" logger <- (tag) is Formatter as pure function rtn:=? `${tag}: ${text}`
INLINE VS MULTI-LINE
Inline form: () is Type as pure (body). Multi-line form: () is Type as pure function followed by indented body.
WHEN TO USE DYNAMIC FUNCTIONS
One-off implementations that do not warrant a named function. Functions that need access to local variables (closures). Building function instances with different captured state.
See Q52 for dynamic function basics. See Q53 for closure capture. See Q588 for function extension basics. See Q591 for comparing function and class hierarchies.
Example
defines module qa.function.dynamicextends defines function //Abstract function contract Formatter as pure abstract -> text as String <- rtn as String? //Named implementation for comparison PlainFormatter is Formatter as pure -> text as String <- rtn as String: text defines program DynamicFunctionExtendsDemo() stdout <- Stdout() //Named implementation stdout.println(PlainFormatter("hello")) //Inline dynamic function (single-line body) upper <- () is Formatter as pure (rtn:=? text.upperCase()) stdout.println(upper("hello")) //Dynamic function with captured variable (multi-line body) tag <- "LOG" logger <- (tag) is Formatter as pure function rtn:=? `${tag}: ${text}` stdout.println(logger("system started")) //Another capture with different value errorTag <- "ERROR" errorLogger <- (errorTag) is Formatter as pure function rtn:=? `${errorTag}: ${text}` stdout.println(errorLogger("disk full")) //All are Formatter type: polymorphic usage formatters <- List() of Formatter formatters += PlainFormatter formatters += upper formatters += logger formatters += errorLogger for item in formatters stdout.println(item("test message"))
Common mistakes
E08120 — A function declared as pure must not mutate variables. The += operator mutates text in place, so the compiler reports E08120. See ek9 -h E08120 for details.
Incorrect:
PlainFormatter is Formatter as pure -> text as String <- rtn as String: text text += "!"
Correct:
PlainFormatter is Formatter as pure -> text as String <- rtn as String: text
Other ways to ask this
- How do I create inline function implementations?
- Can I use dynamic functions with abstract function types?
- How do I extend an abstract function inline?
Coming from another language?
Java: lambdas implement functional interfaces. Python: lambdas are limited to expressions. Rust: closures implement Fn traits. Kotlin: lambdas implement functional types. EK9: dynamic functions extend abstract functions with closure capture.
Keywords: closure, extends, extend, implement, anonymous, capture, abstract, function, inline, dynamic