ek9_introduce_parameter
Appends a new parameter to the enclosing method/function, replaces the selected in-body expression with it and passes the ORIGINAL expression at every call site (Fowler "Introduce Parameter"); answers status, edits[] and conflicts[] (value-expression-not-a-single-expression, type-not-inferable, ...).
When to use it
'Give greet a parameter greeting and use it instead of the literal "Hello "' is one call with file, expression:'"Hello "' and name:'greeting' - the body uses the parameter and every existing call site is passed the original value. Use it (not ek9_change_signature, which adds the parameter but leaves the body unchanged) when a body hard-codes a value callers should be able to vary - in a statement or in the '<- rtn as T: ...' initialiser.
When not to use it
- The value should be a LOCAL variable in the same method - use
ek9_extract_variable. - The value should become a CLASS FIELD (per-instance state, not per-call) - use
ek9_introduce_field. - The value should be a module-level CONSTANT (immutable, shared) - use
ek9_extract_constant. - You need broader signature changes - explicit position, several parameters at once, return type, or purity - use
ek9_change_signature; this tool only APPENDS one parameter.
Details
Parameter type is inferred from the expression unless parameterType is supplied; V1 always APPENDS (no position arg), and when the post-change parameter count reaches 4+ all call sites are rewritten to named-argument form per E11062. Promoting in a method that overrides a trait/supertype contract resolves to the root contract and cascades the parameter across the whole override family (resolved-to-contract advisory). would-fail (gate-caught): the expression references a method-local unresolvable at call sites (E50001) or hides impurity in a pure method (E08130); conflicts: value-expression-not-a-single-expression (bad/partial span), expression-not-in-body, type-not-inferable (supply parameterType), no-promotable-declaration; a name colliding with an existing parameter is an error.
Arguments
| Argument | Type | Required | What it is |
|---|---|---|---|
endColumn | integer | 1-based EXCLUSIVE column of the END of the span (an IDE selection). Omit it - pass the text instead. | |
expression | string | The expression to turn into the parameter, exactly as written (e.g. '"Hello "' - quotes included for a string). Its first occurrence in file, or on 'line' when given. | |
file | string | yes | Workspace-relative path to the .ek9 source file holding the expression (and its enclosing method/function). |
line | integer | Optional 1-based line holding the expression - when it occurs more than once. | |
name | string | yes | Identifier for the new parameter (camelCase by convention); kept verbatim. Rename later with ek9_rename_symbol. |
parameterType | string | Optional explicit parameter type. Inferred from the expression when omitted; supply when inference yields type-not-inferable or you want a wider type than the expression's. | |
startColumn | integer | 1-based column of the START of the span on 'line' (an IDE selection). Omit it - pass the text instead. |
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.
Introduce bad span conflict
Request
{
"dryRun" : true,
"endColumn" : 17,
"file" : "Report.ek9",
"line" : 8,
"newParameterName" : "amount",
"startColumn" : 16
}
Response
{
"conflicts" : [ {
"kind" : "value-expression-not-a-single-expression",
"message" : "The range on line 8 (columns 16–17) does not span a single complete EK9 expression. Adjust startColumn/endColumn to the exact bounds of one expression."
} ],
"edits" : [ ],
"meta" : {
"serverMs" : "<timing>"
},
"risk" : {
"crossesModuleBoundary" : false,
"estimatedSeverity" : "trivial",
"fileCount" : 0,
"lineCount" : 0,
"touchesPublicApi" : false,
"touchesTests" : false
},
"status" : "conflicts",
"summary" : "Cannot introduce parameter on function report — 1 conflict",
"workspaceHash" : "<workspace-hash>",
"wouldBeDiagnostics" : [ ],
"written" : false
}
Field rebound at caller
Request
{
"endColumn" : 32,
"file" : "Tax.ek9",
"line" : 11,
"newParameterName" : "rate",
"startColumn" : 25
}
Response
{
"conflicts" : [ {
"col" : 35,
"file" : "<workspace-root>/Tax.ek9",
"kind" : "threaded-value-changes-meaning",
"line" : 20,
"message" : "`taxRate` is the property `taxRate` declared on line 6 here, but at this call site it would read the property `taxRate` declared on line 17. Not changed: pass this caller its own value with ek9_change_signature (add-parameter with valueForExistingCalls), or introduce the parameter from an expression that reads only values every caller can see."
} ],
"edits" : [ ],
"meta" : {
"serverMs" : "<timing>"
},
"risk" : {
"crossesModuleBoundary" : false,
"estimatedSeverity" : "trivial",
"fileCount" : 0,
"lineCount" : 0,
"touchesPublicApi" : false,
"touchesTests" : false
},
"status" : "conflicts",
"summary" : "Cannot introduce parameter on method charge — 1 conflict",
"workspaceHash" : "<workspace-hash>",
"wouldBeDiagnostics" : [ ],
...
Cut short here: 2 more lines. The whole recorded call.
Introduce promote local apply
Request
{
"endColumn" : 18,
"file" : "Report.ek9",
"line" : 8,
"newParameterName" : "total",
"startColumn" : 7
}
Response
{
"conflicts" : [ ],
"edits" : [ {
"before" : " total <- 10",
"endLine" : 8,
"file" : "Report.ek9",
"startLine" : 8,
"type" : "delete"
}, {
"after" : " report()\n ->\n label as String\n total as Integer",
"before" : " report()\n -> label as String",
"endLine" : 6,
"file" : "Report.ek9",
"startLine" : 5,
"type" : "replace"
}, {
"after" : " report(\"a\", 10)",
"before" : " report(\"a\")",
"endLine" : 13,
"file" : "Report.ek9",
"startLine" : 13,
"type" : "replace"
}, {
"after" : " report(\"b\", 10)",
...
Cut short here: 24 more lines. The whole recorded call.
See also
- Show me in the IDE: Introduce Parameter