Hi,

I have not been able to get an apache groovy jira login to file this
ticket. Would it be possible for one of you to file it on my behalf?  We
are stuck on an older version of Groovy because of this defect.

Thanks,

Stan

On Thu, Sep 24, 2026 at 10:27 PM Jochen Theodorou via dev <
[email protected]> wrote:

> Hi Stan,
>
>
> the situation actually looks even worse to me:
>
> String m(float... x)  { return "float...";  }
> String m(double... x) { return "double..."; }
>
> String m2(float a)  { return "float...";  }
> String m2(double a) { return "double..."; }
> String m2(float a,float x)  { return "float...";  }
> String m2(double a,double x) { return "double..."; }
>
> z = 1
> d = 5.0
> assert m(d) == "double..."
> assert m2(d) == "double..."
> assert m(z) == "float..." // should be double...
> assert m2(z) == "float..." // should be double...
>
> assert m2(z,z) == "float..." // should be double...
> assert m2(z,d) == "float..." // should be double...
> m(z, d) // fails with Ambiguous method overloading
>
> The distance table clearly says:
>
> BD  -> double: 2
> BD  -> float:  4
> int -> double: 8
> int -> float:  10
> Integer -> float: 11
> Integer -> double: 9
>
> which explains the results I expect, but not what we get... which means
> something is actually overruling the distance table or selecting before
> considering it, and doing it different from the distance table. float
> being considered or not here for BigDecimal should actually not have
> played a role in this.
>
> So yes, I think a JIRA issue is more than justified. I could not easily
> find the real reason as of why this happens. It is almost as if this
> distance calculation is ignored (or not even done).
>
> bye Jochen
>
> On 9/25/26 00:26, Stan Brubaker via dev wrote:
> > Hi all,
> >
> > While moving a project from Groovy 3.0.25 to 5.1.3 we hit a dispatch
> change
> > that I have bisected to 4.0.4, and I would like to know whether it was
> > intended before I file a ticket.
> >
> > Given two competing varargs overloads:
> >
> >      public class Overloads {
> >          public static String m(float... x)  { return "float...";  }
> >          public static String m(double... x) { return "double..."; }
> >      }
> >
> > and a script where the decimal literal is untyped, so a BigDecimal:
> >
> >      import static Overloads.*
> >      z = 1
> >      d = 5.0
> >      println m(d)
> >      println m(z, d)
> >      println m(5, z, d)
> >      println m(5, 2, 3, z, d)
> >
> > Groovy 4.0.3 and all of 3.0.x print "double..." four times. Groovy 4.0.4
> > through 6.0.0 print:
> >
> >      m(d)             -> double...
> >      m(z, d)          -> GroovyRuntimeException: Ambiguous method
> > overloading
> >      m(5, z, d)       -> float...
> >      m(5, 2, 3, z, d) -> float...
> >
> > So a BigDecimal is now narrowed to float (about 7 significant digits
> rather
> > than 16) when accompanied by two or more integral arguments, and the
> > two-argument form fails outright where it previously worked.
> >
> > The cause appears to be commit ef7026317f, "GROOVY-8045: support
> > coercion for
> > variadic parameter", which changed the predicate gating varargs
> > applicability
> > in ParameterTypes.isValidVargsMethod:
> >
> >      // 4.0.3
> >      if (MetaClassHelper.isAssignableFrom(clazz, arguments[i])) continue;
> >      // 4.0.4
> >      if (!componentType.isAssignableFrom(argumentTypes[i])) { return
> > false; }
> >
> > MetaClassHelper.isAssignableFrom and CachedClass.isAssignableFrom
> disagree
> > about BigDecimal -> float. With a class exposing only a float...
> > overload, so
> > no competing candidate and no distance comparison involved, 4.0.3 raises
> > MissingMethodException for m(BigDecimal) while 4.0.4 accepts it.
> >
> > So float... previously was not a candidate at all and double... won by
> > default. Now both are applicable and selection falls through to the
> distance
> > algorithm, which is itself unchanged -- PRIMITIVE_DISTANCE_TABLE, the
> > varargs
> > accumulation in calculateParameterDistance, and
> MetaClassImpl.handleMatches
> > are byte-identical between 3.0.25 and 5.1.3. Summing its per-argument
> costs,
> > each integral argument biases toward float by 2 while the lone BigDecimal
> > biases toward double by only 2, which produces exactly the
> arity-dependent
> > results above.
> >
> > Since GROOVY-8045 is about implicit closure coercion, I suspect the
> numeric
> > side effect was collateral: it shipped in a patch release with no
> > breaking-change note, and it was not backported to 3.0.x, which still
> > selects
> > double... as of 3.0.25. But I may well be missing context, hence this
> mail
> > rather than a Jira issue.
> >
> > Two questions:
> >
> > 1. Was widening varargs applicability to include BigDecimal -> float
> >     intended?
> > 2. If so, should a lossy narrowing be able to win on summed distance
> against
> >     the lossless widenings of its accompanying arguments?
> >
> > Reproduced on Temurin 17, 21, 25 and 27 on Linux x64, plain dynamic
> > Groovy --
> > no @CompileStatic or @TypeChecked, no metaprogramming, no third-party
> > libraries. I could not find an existing issue; the closest are
> GROOVY-5490
> > (open, same distance algorithm but inheritance distance among reference
> > types) and GROOVY-1937 (fixed in 1.1-beta-2, establishing BigDecimal ->
> > double for varargs).
> >
> > Happy to file this in Jira with the full analysis, or to submit a PR
> with a
> > failing test, if that is useful.
> >
> > Encountered in Deephaven Community Core (Apache-2.0), whose generated
> > io.deephaven.function.Numeric exposes max/min over the full primitive
> > varargs
> > ladder, so max(5, 2, 3, 1, 5.0) changed from Double to Float and max(1,
> 5.0)
> > began throwing. A typed literal (5.0d) still selects double... on every
> > version from 3.0.25 through 6.0.0.
> >
> > Thanks,
> > Stan
>
>

Reply via email to