Paul King created GROOVY-12217:
----------------------------------

             Summary: Decide on a fat-free twin for sum (positional collision 
with the initialValue overload)
                 Key: GROOVY-12217
                 URL: https://issues.apache.org/jira/browse/GROOVY-12217
             Project: Groovy
          Issue Type: Sub-task
            Reporter: Paul King


h3. Summary

Split out of the fold/reduce sub-task (GROOVY-12205 scope). Unlike every other 
fat-free method, {{sum}}'s functional twin cannot be added mechanically: it 
would land on the same single trailing-argument slot as the existing 
{{sum(Iterable, Object initialValue)}} overload, changing overload resolution 
for some existing calls. This item is for the compatibility decision before any 
implementation.

h3. Why sum is different

{{sum}} overloads its single trailing argument between two meanings:
* {{sum(Iterable, Object initialValue)}} — sum the elements starting from 
{{initialValue}}.
* {{sum(Iterable, Closure)}} — map each element, then sum.

The natural twin of the second is {{sum(Iterable, Function<? super T, ?>)}}. 
But a {{Function}} is an {{Object}} and is more specific, so any argument 
assignable to {{Function}} would now bind to the mapping twin instead of the 
{{initialValue}} overload. This is unavoidable with a same-name, same-arity 
twin.

(By contrast, {{inject}}/{{injectAll}} keep the reduce function in a distinct 
position after an explicit {{initialValue}} parameter, so they have no such 
collision.)

h3. Practical blast radius

The reroute only affects arguments that are {{Function}} instances. Passing 
such a value as {{sum}}'s initial value already fails today: 
{{[1,2,3].sum(someFunction)}} throws {{MissingMethodException: No signature of 
method: plus for class: ...Function}} (a {{Function}} has no {{plus}}). So the 
rerouted calls are ones that are already broken, not working code. The only 
genuine regression would be an object that is simultaneously a {{Function}} and 
a valid summation seed (defines {{plus}}) — contrived, but not provably 
impossible in a large codebase.

h3. Methods that would be affected (if we proceed)

{{sum}} forms lacking a twin (6): {{Iterable}}, {{Iterator}}, each with and 
without {{initialValue}}, {{T[]}}, {{T[]}}+init. Proposed type: {{Function<? 
super T, ?>}}.

h3. Options

# *Proceed*, justified by "rerouted calls already throw today", with a targeted 
grep of the codebase + ecosystem and a one-release changelog note.
# *Defer* to a dedicated compatibility pass (recommended) — keeps the 
mechanical batches clean and gives {{sum}} a proper review, possibly with a 
deprecation/transition path.
# *Exclude* the {{sum}} mapping twin entirely — arguably fits GROOVY-12205's 
own "unless the JDK already provides the equivalent" carve-out, since a mapped 
sum is expressible as {{list.stream().mapToInt(f).sum()}} or 
{{list.collect(f).sum()}}.

h3. Recommendation

Defer (option 2). The collision is unique to {{sum}}, the twin cannot be added 
without changing resolution semantics, and the value of the twin is low given 
the JDK stream alternatives.




--
This message was sent by Atlassian Jira
(v8.20.10#820010)

Reply via email to