ek9_expand_default_operator
Replaces the 'default operator' declaration with the explicit body the compiler would synthesise from the fields, ready to customise; answers status, edits[] and summary, a missing default line as conflicts[] (target-not-a-default-operator).
When to use it
'Expand Order's default operator <=> so I can customise it' is one call with symbol:'Order' and operator:'<=>' - omit operator to expand the bare block.
When not to use it
- Going the OTHER way - replacing an explicit operator body with the 'default operator' form (cleanup) - use
ek9_collapse_to_default_operator. - The operator doesn't exist on the target yet (default OR explicit) - use
ek9_add_operatorto author from scratch. - The operator should be REMOVED entirely, not expanded - use
ek9_safe_delete. - Operator outside the defaultable set (==, <>, <=>, <, >, <=, >=, $, $$, ?, #?, :=:) - no default form exists; author it with
ek9_add_operatorbody:'explicit'.
Details
Class / record / component targets with at least one field - traits and field-less constructs are refused (no properties to derive a body from). mode is inferred (operator → one, none → all); a contradicting mode is a mode-contradicts-arguments conflict. The 'after' body mirrors the compiler's synthesis: == ANDs each property's ==, <=> cascades to the first non-zero in declaration order (< <= > >= delegate to <=>), ? ANDs each _isSet, #? XORs each _hashcode, $ interpolates the fields, :=: copies each field; all emit 'as pure' except :=:, chaining via super.<op>(...) first when a real superclass declares the operator. Conflict kinds: target-not-a-default-operator (no such 'default operator' line - a hand-written body is changed with ek9_insert_statements), target-operator-not-supported-for-default; the all form skips operators already explicitly declared and errors when none remain.
Arguments
| Argument | Type | Required | What it is |
|---|---|---|---|
file | string | The EK9 source file - OPTIONAL when symbol is a construct name; required to anchor on a member or a use site. | |
line | integer | IDE refinement: the 1-based line of the 'default operator' declaration. Omit it - the declaration is found by symbol + operator. | |
mode | string: one | all | Optional - inferred: operator given → one, none → all. | |
operator | string | The one operator to expand, in EK9 source form ('==', '<=>', '$'). Omit it to expand the bare 'default operator' block into every defaultable operator. | |
symbol | string | yes | The class, record or component holding the default operator - a bare name ('Order') finds its file workspace-wide; 'mod::Order' when the name is declared in two modules. |
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.
Single finds line by name apply
Request
{
"constructName" : "Order",
"cursorLine" : 7,
"file" : "Order.ek9",
"mode" : "single",
"operator" : "$"
}
Response
{
"conflicts" : [ ],
"edits" : [ {
"after" : " operator $ as pure\n <- rtn as String: `Order(${name})`",
"endLine" : 8,
"file" : "Order.ek9",
"startLine" : 8,
"type" : "replace"
} ],
"meta" : {
"serverMs" : "<timing>"
},
"resolvedPath" : "<workspace-root>/Order.ek9",
"risk" : {
"crossesModuleBoundary" : false,
"estimatedSeverity" : "trivial",
"fileCount" : 1,
"lineCount" : 1,
"touchesPublicApi" : false,
"touchesTests" : false
},
"status" : "applied",
"summary" : "Expanded 'default operator $' to skeleton in Order",
"workspaceHash" : "<workspace-hash>",
...
Cut short here: 3 more lines. The whole recorded call.
Single on hand written operator conflicts
Request
{
"constructName" : "Order",
"cursorLine" : 7,
"file" : "Order.ek9",
"mode" : "single",
"operator" : "$"
}
Response
{
"conflicts" : [ {
"description" : "Order has no 'default operator $' line (line 7 is 'operator $ as pure') - nothing was written. An operator that already has a body is changed with ek9_insert_statements(symbol:'Order', method:'$', anchor:{position:'replace'}, statements:['rtn: <expression>']).",
"file" : "Order.ek9",
"kind" : "target-not-a-default-operator"
} ],
"edits" : [ ],
"meta" : {
"serverMs" : "<timing>"
},
"risk" : {
"crossesModuleBoundary" : false,
"estimatedSeverity" : "trivial",
"fileCount" : 0,
"lineCount" : 0,
"touchesPublicApi" : false,
"touchesTests" : false
},
"status" : "conflicts",
"summary" : "Order has no 'default operator $' line (line 7 is 'operator $ as pure') - nothing was written. An operator that already has a body is changed with ek9_insert_statements(symbol:'Order', method:'$', anchor:{position:'replace'}, statements:['rtn: <expression>']).",
"workspaceHash" : "<workspace-hash>",
"wouldBeDiagnostics" : [ ],
"written" : false
}
Expand all apply
Request
{
"constructName" : "MyRecord",
"cursorLine" : 7,
"file" : "MyRecord.ek9",
"mode" : "all"
}
Response
{
"conflicts" : [ ],
"edits" : [ {
"after" : " operator <=> as pure\n -> other as MyRecord\n <- rtn as Integer: 0\n rtn: name <=> other.name\n\n override operator ? as pure\n <- rtn as Boolean: name?\n\n operator $ as pure\n <- rtn as String: `MyRecord(${name})`\n\n operator $$ as pure\n <- rtn as JSON: JSON()\n\n operator #? as pure\n <- rtn as Integer: #?name\n\n operator :=:\n -> source as MyRecord\n name :=: source.name",
"endLine" : 7,
"file" : "MyRecord.ek9",
"startLine" : 7,
"type" : "replace"
} ],
"meta" : {
"serverMs" : "<timing>"
},
"resolvedPath" : "<workspace-root>/MyRecord.ek9",
"risk" : {
"crossesModuleBoundary" : false,
"estimatedSeverity" : "trivial",
"fileCount" : 1,
"lineCount" : 1,
"touchesPublicApi" : false,
"touchesTests" : false
},
"status" : "applied",
"summary" : "Expanded 'default operator' to 20 skeleton lines in MyRecord",
"workspaceHash" : "<workspace-hash>",
...
Cut short here: 3 more lines. The whole recorded call.
See also
- Show me in the IDE: Expand Default Operator