ek9_create_dynamic_class

Inserts `variableName <- (captures) trait of T as class` (or the tuple / generic form) with its members after the line, auto-adding `default operator ?` for captures; answers status, edits[] and summary, with a would-fail carrying the compiler's own diagnostics (unimplemented abstract methods named).

Category: Editor · Compare: IntelliJ "Convert to anonymous class" / anonymous-class generate action

When to use it

'An inline class implementing Describable over the captured prefix' is one call with file, line (the body line it goes after), variableName and traits:[{name}].

When not to use it

Details

Form is set by `form` or auto-detected (traits present -> trait; baseType present -> generic; else tuple); className is a module-level TYPE distinct from the variableName receiver — mandatory for tuple, optional (anonymous) for trait/generic. Scratch-compilation is the sole validator: would-fail carries the compiler's own diagnostics (unresolved trait/base, unimplemented abstract methods, name collision E01040, purity, capture syntax E06230/E06240/E02040), while the fresh binding's expected E08090 (scaffold not yet referenced) is tolerated so a clean insert stays ready. conflicts kinds: target-not-function-body (bad anchor), dynamic-body-not-supported (nesting into a dynamic body, v1 limit).

Arguments

ArgumentTypeRequiredWhat it is
baseTypestringGeneric-extension form: the parameterised base (e.g. `Iterator of Integer`, `Function of (String, Integer)`).
capturesarray of objectCapture list (may be empty). Each entry: {fieldName?, sourceExpression}. Captures are by-pointer-value — mutating a captured object inside the class is visible to the caller (copy via :=: before capture for isolation). A non-empty list auto-adds `default operator ?`.
classNamestringThe dynamic class's own name — the grammar identifier, a module-level TYPE, distinct from variableName. REQUIRED for the tuple form; optional (anonymous when omitted) for trait/generic forms.
filestringyesThe .ek9 source file containing the host body (workspace-relative; an absolute path inside the workspace is accepted).
formstring: trait | tuple | genericWhich grammar alternative to emit. Auto-detected when omitted: traits present → trait; baseType present → generic; otherwise tuple.
inheritanceKeywordstring: is | extendsGeneric-extension form only: `is` and `extends` are synonyms. Default: `is`.
lineintegeryes1-based line AFTER which the dynamic class 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 class with captures cannot be hoisted above them).
membersstringMulti-line aggregateParts body: fields, then methods, then operators, in grammar order (the caller owns ordering). Required for the tuple form UNLESS at least one capture is supplied (captures become the tuple's fields + an auto `default operator ?`). Omit for trait/generic to scaffold header-only (the dryRun would-fail then names the abstract methods to implement). If you author an `operator ?`, the auto `default operator ?` is suppressed.
stubAbstractMethodsbooleanWhen true, scaffold the OUTSTANDING abstract methods the base owes, each as a compiling `override … //AI: complete method` stub (require-guarded params, guard-first return). Generic form: the base type's abstract methods with conceptual type parameters substituted (`Iterator of Integer` -> `next() as Integer`). Trait form: the traits' unimplemented abstract methods. Tuple form has no abstract obligations (no-op). Deduped against methods you already supply in `members` — only the missing ones are added. The result is a SCAFFOLD: bodies are placeholders behind `//AI:` markers, and the fresh variable's E08090 (not-yet-referenced) is tolerated so the dryRun is `ready`. Leave false to instead have the would-fail simply NAME the methods to add.
traitsarray of objectTrait form: the traits to implement or delegate. Each {name, by?}. Order preserved.
variableNamestringyesLocal variable that receives the instance (e.g. wrapper, iterator1). Emitted as `variableName <- …`.

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 12 recorded are shown.

Conflict not function body

Request

{
  "captures" : [ {
    "sourceExpression" : "prefix"
  } ],
  "file" : "Dyn.ek9",
  "insertAfterLine" : 2,
  "traits" : [ {
    "name" : "Describable"
  } ],
  "variableName" : "w"
}

Response

{
  "conflicts" : [ {
    "kind" : "target-not-function-body",
    "message" : "Line 2 is not inside a function, program or method body — a dynamic class has no host to live in there. Pick a line inside a callable body, after the captured variables are declared."
  } ],
  "edits" : [ ],
  "meta" : {
    "serverMs" : "<timing>"
  },
  "risk" : {
    "crossesModuleBoundary" : false,
    "estimatedSeverity" : "trivial",
    "fileCount" : 0,
    "lineCount" : 0,
    "touchesPublicApi" : false,
    "touchesTests" : false
  },
  "status" : "conflicts",
  "summary" : "Cannot insert dynamic class w — 1 conflict",
  "workspaceHash" : "<workspace-hash>",
  "wouldBeDiagnostics" : [ ],
  "written" : false
}

Trait stub abstract methods

Request

{
  "dryRun" : true,
  "file" : "Dyn.ek9",
  "insertAfterLine" : 12,
  "stubAbstractMethods" : true,
  "traits" : [ {
    "name" : "Describable"
  } ],
  "variableName" : "d"
}

Response

{
  "conflicts" : [ ],
  "edits" : [ {
    "after" : "      d <- () trait of Describable as class\n        override describe() as pure\n          <- rtn as String: String()\n          //AI: complete method",
    "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 class d (trait of [Describable]) at line 13",
  "workspaceHash" : "<workspace-hash>",
  "wouldBeDiagnostics" : [ ],
...

Cut short here: 2 more lines. The whole recorded call.

Stub dedups provided members

Request

{
  "baseType" : "Iterator of Integer",
  "dryRun" : true,
  "file" : "Dyn.ek9",
  "insertAfterLine" : 12,
  "members" : "override hasNext() as pure\n  <- rtn as Boolean: true",
  "stubAbstractMethods" : true,
  "variableName" : "iter"
}

Response

{
  "conflicts" : [ ],
  "edits" : [ {
    "after" : "      iter <- () is Iterator of Integer as class\n        override hasNext() as pure\n          <- rtn as Boolean: true\n\n        override next()\n          <- rtn as Integer: 0\n          //AI: complete method",
    "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 class iter (is Iterator of Integer) at line 13",
  "workspaceHash" : "<workspace-hash>",
  "wouldBeDiagnostics" : [ ],
...

Cut short here: 2 more lines. The whole recorded call.

See also