E11069: nested call chain exceeds one level - extract intermediate variable for readability
What went wrong
A nested call chain deeper than one level was detected. EK9 supports single-level functional chaining (e.g., getTransformer("upper")("text")) but rejects deeper nesting as it forces inside-out mental evaluation that obscures the types and intent of the code.
Worked examples
Compilable examples related to this error:
- ek9 -q 1342 (Why does EK9 reject a deeply nested higher-order call...)
Rationale
Single-level chaining is idiomatic in functional programming: in 'getProcessor("upper")("hello")' the reader sees getProcessor returns a delegate, and that delegate accepts "hello". The types are clear from context.
Deeper chains force reverse-order mental evaluation. To understand 'getMaker("simple")("seed")("text")' (the [EXAMPLE] section below), you must:
- Evaluate getMaker("simple") - what type does it return?
- Call that result with ("seed") - what type does THAT return?
- Call that result with ("text") - finally get the answer.
This is the same cognitive problem as C's nested pointer dereferences: (*(**fp)(x))(y). Each level multiplies the mental effort required to trace types through the chain.
Extracting intermediate variables documents the types and intent: a 'maker' holding getMaker's Maker, a 'transformer' holding what the maker makes, then the String the transformer gives.
Each line is independently understandable. Variable names document what each intermediate value represents. Debugging can inspect each step. Code review can verify each type transition.
How to fix it
Extract intermediate variables to break the chain: give each delegate a call returns its own named variable, and call that. Single-level chaining remains valid. The fix in the [EXAMPLE] section below shows both: a single-level chain 'getTransformer(UPPER_TRANSFORM)("single level is fine")', and the same call decomposed through a named 'transformer'.
See also
Examples
Every example is compiled by the EK9 compiler: the first fails exactly as captioned, the others fix it.
Fails with E11069: nested call chain exceeds one level - extract intermediate variable for readability
#!ek9 defines module error.e11069.bad defines function Transformer() as pure abstract -> input as String <- output as String? UpperTransformer() extends Transformer as pure -> input as String <- output as String: input.upperCase() Maker() as abstract -> seed as String <- transformer as Transformer? SimpleMaker() extends Maker -> seed as String <- transformer as Transformer: UpperTransformer getMaker() -> kind as String <- maker as Maker: SimpleMaker if kind == "simple" maker: SimpleMaker //Two levels deep: getMaker returns Maker, Maker returns Transformer, Transformer returns String checkTwoLevelChain() <- result as String? result: getMaker("simple")("seed")("text")
Fixed: Name the intermediate result
#!ek9 defines module error.e11069.good defines constant //'upper' appeared three times, which is E11065 (repeated magic literal). Naming it keeps this //positive control clean - it exists to say nothing about call-chain depth, not to trip a //different rule. UPPER_TRANSFORM <- "upper" defines function Transformer() as pure abstract -> input as String <- output as String? UpperTransformer() extends Transformer as pure -> input as String <- output as String: input.upperCase() getTransformer() -> mode as String <- transformer as Transformer: UpperTransformer if mode == "lower" transformer: UpperTransformer //Single-level chaining: valid functional pattern checkSingleLevelChain() <- result as String? result: getTransformer(UPPER_TRANSFORM)("single level is fine") //Single-level chaining with objectAccess: also valid checkSingleLevelWithChain() <- result as String? result: getTransformer(UPPER_TRANSFORM)(" chained ").trim() //Direct function call: not a chain at all checkDirectCall() <- result as String? processor as Transformer: UpperTransformer result: processor("direct delegate") //Decomposed two-level: the correct way to handle depth checkDecomposedChain() <- result as String? transformer <- getTransformer(UPPER_TRANSFORM) result: transformer("decomposed is clear")
Questions and answers
These Q&A entries show E11069 and its fix: