ek9_add_field
Inserts the field declaration at the construct's canonical field position; answers status, edits[] and summary, a clashing name as conflicts[] (name-collision).
When to use it
'Add a field to CustomerOrder' is one call with symbol:'CustomerOrder', fieldName and defaultValue (or rawDeclaration:'logger as Logger!') - no file or line.
When not to use it
- Adding a METHOD or CONSTRUCTOR, not a field - use
ek9_add_method/ek9_add_constructor. - The target construct doesn't exist yet - create it with
ek9_new_constructfirst. - Renaming or removing an existing field - use
ek9_rename_field/ek9_remove_field. - Traits, functions, services, applications, programs, text - these grammatically have no fields; the tool returns a target-construct-is-not-fielded conflict.
Details
Two forms: structured (fieldName + defaultValue; defaultValue REQUIRED for records) or raw (rawDeclaration as typed, e.g. `name as String?` or `logger as Logger!`); mode is inferred from which is given and a contradicting mode is a conflict. Visibility is genus-fixed: class/component fields are always private, record fields always public - no access-modifier syntax exists. A pre-existing field name is a name-collision conflict (structured) or hard error (raw); an UNINITIALISED field can trip E07175/E07170 (public no-arg ctor would build a partial object) → would-fail - fix with an initialiser, a private no-arg ctor, or an explicit ctor.
Arguments
| Argument | Type | Required | What it is |
|---|---|---|---|
defaultValue | string | Default value expression for the field, e.g. '0', '""', 'String()'. Required for records in the structured form. | |
fieldName | string | The new field's name (structured form) - with 'type' or 'defaultValue'; a name alone renders a typeless field (E07110). | |
file | string | The EK9 source file - OPTIONAL when symbol is a construct name; required to anchor on a member or a use site. | |
mode | string: structured | raw | Optional - inferred: rawDeclaration → raw, fieldName → structured. | |
rawDeclaration | string | The whole declaration line as you would type it (raw form), e.g. 'name as String?' or 'logger as Logger!' (DI). | |
symbol | string | yes | The class, record or component the field is added to - a bare name ('Order') finds its file workspace-wide; 'mod::Order' when the name is declared in two modules. |
type | string | The field's type in the structured form, e.g. 'Float', 'List of String' - rendered 'name as Type: Type()' (present, unset until assigned) unless defaultValue is given. | |
withConstructor | boolean | Insert a NEW pure constructor taking this field, in the SAME change - the fields-mode rendering ek9_add_constructor mode:'fields' uses. Only applies when the field is left with no value ('name as Type?' / rawDeclaration ending '?', or the structured form with 'type' and no 'defaultValue') - that is the one shape a publicly-constructible class can leave uninitialised (E07170/E08070/E08060) until a second ek9_add_constructor call lands one; any other form already has what it needs and the option is a no-op. Default false. |
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 11 recorded are shown.
Add structured field dry run ready
Request
{
"constructName" : "Greeter",
"defaultValue" : "0",
"dryRun" : true,
"fieldName" : "cachedCount",
"file" : "Greeter.ek9",
"mode" : "structured"
}
Response
{
"conflicts" : [ ],
"edits" : [ {
"after" : " cachedCount <- 0",
"endLine" : 7,
"file" : "Greeter.ek9",
"startLine" : 7,
"type" : "insert"
} ],
"meta" : {
"serverMs" : "<timing>"
},
"risk" : {
"crossesModuleBoundary" : false,
"estimatedSeverity" : "trivial",
"fileCount" : 1,
"lineCount" : 1,
"touchesPublicApi" : false,
"touchesTests" : false
},
"status" : "ready",
"summary" : "Added field 'cachedCount' to Greeter",
"workspaceHash" : "<workspace-hash>",
"wouldBeDiagnostics" : [ ],
...
Cut short here: 2 more lines. The whole recorded call.
Add structured field apply
Request
{
"constructName" : "Greeter",
"defaultValue" : "0",
"fieldName" : "cachedCount",
"file" : "Greeter.ek9",
"mode" : "structured"
}
Response
{
"conflicts" : [ ],
"edits" : [ {
"after" : " cachedCount <- 0",
"endLine" : 7,
"file" : "Greeter.ek9",
"startLine" : 7,
"type" : "insert"
} ],
"meta" : {
"serverMs" : "<timing>"
},
"resolvedPath" : "<workspace-root>/Greeter.ek9",
"risk" : {
"crossesModuleBoundary" : false,
"estimatedSeverity" : "trivial",
"fileCount" : 1,
"lineCount" : 1,
"touchesPublicApi" : false,
"touchesTests" : false
},
"status" : "applied",
"summary" : "Added field 'cachedCount' to Greeter",
"workspaceHash" : "<workspace-hash>",
...
Cut short here: 3 more lines. The whole recorded call.
No type refusal example lands
Request
{
"rawDeclaration" : "total as Float: Float()",
"symbol" : "Order"
}
Response
{
"conflicts" : [ ],
"edits" : [ {
"after" : " total as Float: Float()",
"endLine" : 8,
"file" : "task.ek9",
"startLine" : 8,
"type" : "insert"
} ],
"meta" : {
"serverMs" : "<timing>"
},
"resolvedPath" : "<workspace-root>/task.ek9",
"risk" : {
"crossesModuleBoundary" : false,
"estimatedSeverity" : "trivial",
"fileCount" : 1,
"lineCount" : 1,
"touchesPublicApi" : false,
"touchesTests" : false
},
"status" : "applied",
"summary" : "Added field 'total as Float: Float()' to Order",
"workspaceHash" : "<workspace-hash>",
...
Cut short here: 3 more lines. The whole recorded call.
See also
- Show me in the IDE: Chapter 16: a class, built
- Show me in the IDE: Chapter 17: an abstract type and its subtypes, built
- Show me in the IDE: Chapter 18: traits and delegation, built
- Show me in the IDE: Chapter 23: the game, built and played
- Fixes E05030