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:
Formatter as pure abstract -> text as String <- rtn as String?
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
E50001 — A pure function cannot call non-pure methods. Pure functions must not produce side effects. See ek9 -h E50001 for details.
Incorrect:
PlainFormatter is Formatter as pure -> text as String <- rtn as String: text stdout.println(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: anonymous, implement, extend, extends, closure, dynamic, inline, function, abstract, capture