ek9_create_dynamic_function
Inserts `variableName <- (captures) is|extends Base as [pure] function` with its body (or an inline `(expr)`, or an //AI: stub) after the line; answers status, edits[] and summary, with a would-fail carrying the compiler's own diagnostics.
When to use it
'A closure gt over the captured min implementing discriminator' is one call with file, line (the line it goes after), variableName, baseType and bodyExpression.
When not to use it
- You need a trait implementation (with trait of T) or a tuple-style class - use
ek9_create_dynamic_class. - You are authoring a NAMED, module-level reusable function - use
ek9_new_constructmode:'function'. - You are factoring an existing block of code into a function - use
ek9_extract_method; this tool creates from scratch.
Details
Single-mode - the syntactic variant is derived from the args: body -> multi-line block; bodyExpression -> inline `(expr)` for a named base, promoted to block for a parameterised base (grammar makes `function` mandatory there); both omitted -> `//AI:` scaffold stub. pure and inheritanceKeyword (is|extends) auto-detect from the base (is + non-pure for a user base; extends + pure for a pure built-in super), both overridable. Conflict kinds: target-not-function-body (escalation - anchor line not inside a callable body), dynamic-body-not-supported (nesting inside a dynamic body, V1 refusal), bodyless-stub-needs-body (a no-return base like Consumer/Acceptor needs a body); everything else - base unresolved, purity mismatch, capture syntax E06230/E06240/E02040 - surfaces as the scratch-compile's own diagnostics (the fresh binding's expected E08090 is tolerated).
Arguments
| Argument | Type | Required | What it is |
|---|---|---|---|
baseType | string | yes | The abstract function being implemented: a user-defined function name in scope, or a parameterised built-in (e.g. `Function of (Integer, String)`, `Predicate of Integer`, `Consumer of String`). |
body | string | Multi-line body. Mutually exclusive with bodyExpression. Refers to the base function's parameter names and its return-variable name. Omit BOTH body and bodyExpression to scaffold a `//AI: provide implementation` stub (block form + default-initialised inherited return) — supported only for a base that RETURNS a value; a no-return base (Consumer/BiConsumer/Acceptor/BiAcceptor) requires a body and a bodyless request is refused. | |
bodyExpression | string | Single-expression inline body (e.g. `rtn: number > threshold`). Mutually exclusive with body. For a NAMED base emitted inline as `(<expr>)`; for a PARAMETERISED base it is promoted to the block form (EK9's grammar makes the `function` keyword mandatory there). | |
captures | array of object | Capture list (may be empty). Each entry: {fieldName?, sourceExpression}. Captures are by-pointer-value — mutating the captured object inside the closure is visible to the caller (copy via :=: before capture for isolation). | |
file | string | yes | The .ek9 source file containing the host body (workspace-relative; an absolute path inside the workspace is accepted). |
inheritanceKeyword | string: is | extends | `is` and `extends` are synonyms. Default: `extends` for a parameterised (generic) base, `is` otherwise. | |
line | integer | yes | 1-based line AFTER which the dynamic function is inserted (read it from ek9_read_file lineNumbers:true). Must be inside a function/program/method body and AFTER the captured variables are declared (a closure with captures cannot be hoisted above them). |
pure | boolean | Emit `as pure`. Default: auto — true for a pure built-in super (Predicate/Function/Consumer/...), false otherwise. Must match the base's purity or the scratch-compile reports a purity mismatch. | |
variableName | string | yes | Local variable that receives the closure (e.g. gt, transformer, predicate1). |
It also takes the arguments every tool takes.
Recorded calls
Real calls, recorded against small projects and checked on every build - a changed answer fails it. 3 of the 9 recorded are shown.
Parameterised inline promoted
Request
{
"baseType" : "Predicate of String",
"bodyExpression" : "r: t?",
"dryRun" : true,
"file" : "Dyn.ek9",
"insertAfterLine" : 12,
"variableName" : "gt"
}
Response
{
"conflicts" : [ ],
"edits" : [ {
"after" : " gt <- () extends Predicate of String as pure function\n r: t?",
"endLine" : 13,
"file" : "Dyn.ek9",
"startLine" : 13,
"type" : "insert"
} ],
"meta" : {
"serverMs" : "<timing>"
},
"risk" : {
"crossesModuleBoundary" : false,
"estimatedSeverity" : "trivial",
"fileCount" : 1,
"lineCount" : 1,
"touchesPublicApi" : false,
"touchesTests" : false
},
"status" : "ready",
"summary" : "Would insert dynamic function gt (extends Predicate of String, pure, block) at line 13",
"workspaceHash" : "<workspace-hash>",
"wouldBeDiagnostics" : [ ],
...
Cut short here: 2 more lines. The whole recorded call.
Builtin super purity
Request
{
"baseType" : "Predicate of String",
"bodyExpression" : "r: t?",
"dryRun" : true,
"file" : "Dyn.ek9",
"insertAfterLine" : 12,
"variableName" : "isSet"
}
Response
{
"conflicts" : [ ],
"edits" : [ {
"after" : " isSet <- () extends Predicate of String as pure function\n r: t?",
"endLine" : 13,
"file" : "Dyn.ek9",
"startLine" : 13,
"type" : "insert"
} ],
"meta" : {
"serverMs" : "<timing>"
},
"risk" : {
"crossesModuleBoundary" : false,
"estimatedSeverity" : "trivial",
"fileCount" : 1,
"lineCount" : 1,
"touchesPublicApi" : false,
"touchesTests" : false
},
"status" : "ready",
"summary" : "Would insert dynamic function isSet (extends Predicate of String, pure, block) at line 13",
"workspaceHash" : "<workspace-hash>",
"wouldBeDiagnostics" : [ ],
...
Cut short here: 2 more lines. The whole recorded call.
Bodyless stub user base
Request
{
"baseType" : "discriminator",
"dryRun" : true,
"file" : "Dyn.ek9",
"insertAfterLine" : 12,
"variableName" : "gt"
}
Response
{
"conflicts" : [ ],
"edits" : [ {
"after" : " gt <- () is discriminator as function\n rtn: false\n //AI: provide implementation",
"endLine" : 13,
"file" : "Dyn.ek9",
"startLine" : 13,
"type" : "insert"
} ],
"meta" : {
"serverMs" : "<timing>"
},
"risk" : {
"crossesModuleBoundary" : false,
"estimatedSeverity" : "trivial",
"fileCount" : 1,
"lineCount" : 1,
"touchesPublicApi" : false,
"touchesTests" : false
},
"status" : "ready",
"summary" : "Would insert dynamic function gt (is discriminator, stub) at line 13",
"workspaceHash" : "<workspace-hash>",
"wouldBeDiagnostics" : [ ],
...
Cut short here: 2 more lines. The whole recorded call.
See also
- Show me in the IDE: Create Dynamic Function