paulk-asert commented on PR #2690:
URL: https://github.com/apache/groovy/pull/2690#issuecomment-4956050602

   Claude recommends the following 
   
   Here's the concrete recommendation for #2690 — a single total, spec-stable 
ordering used by both helpers.
   
   ## The comparator
   
   ```java
   /**
    * Orders by name, then parameter types, then return type. This is a total 
order:
    * the JVM forbids two methods in one class sharing a name and descriptor, 
and the
    * descriptor is exactly the parameter types plus the return type.
    */
   private static int compareMethods(final Method m1, final Method m2) {
       int c = m1.getName().compareTo(m2.getName());
       if (c != 0) return c;
       c = compareParameterTypes(m1.getParameterTypes(), 
m2.getParameterTypes());
       if (c != 0) return c;
       return 
m1.getReturnType().getName().compareTo(m2.getReturnType().getName());
   }
   
   private static int compareParameterTypes(final Class<?>[] p1, final 
Class<?>[] p2) {
       int c = Integer.compare(p1.length, p2.length);
       if (c != 0) return c;
       for (int i = 0; i < p1.length; i += 1) {
           c = p1[i].getName().compareTo(p2[i].getName());
           if (c != 0) return c;
       }
       return 0;
   }
   
   public static Method[] getDeclaredMethodsSorted(final Class<?> type) {
       Method[] methods = type.getDeclaredMethods(); // fresh array; safe to 
sort in place
       Arrays.sort(methods, ReflectionUtils::compareMethods);
       return methods;
   }
   
   public static Constructor<?>[] getDeclaredConstructorsSorted(final Class<?> 
type) {
       Constructor<?>[] constructors = type.getDeclaredConstructors();
       // name is always <init> and the return type always void, so the 
parameters decide
       Arrays.sort(constructors, (c1, c2) ->
           compareParameterTypes(c1.getParameterTypes(), 
c2.getParameterTypes()));
       return constructors;
   }
   ```
   
   ## Why this shape
   
   **The return type is mandatory, and it is the whole point.** Leave it out 
and a bridge method ties with the method it bridges.
   
   **Parameters before return type**, so a bridge sorts adjacent to the method 
it bridges and overloads group by signature. 
`CachedMethod.compareToCachedMethod` (`CachedMethod.java:126`) orders name → 
return type → parameters instead; either is total, and it's worth citing as the 
in-repo precedent that *already* includes the return type for exactly this 
reason. Pick one and be consistent.
   
   **Explicit keys rather than `Method::toString`.** The PR's current 
`thenComparing(Method::toString)` is genuinely correct — `toString()` includes 
the return type, so it is total — but its format is unspecified, which means 
byte-identical output across JDK versions rests on an implementation detail, 
and it rebuilds a long string on every comparison. Comparing class names is 
spec-stable and cheaper.
   
   ## And drop the fields
   
   Delete `getDeclaredFieldsSorted` and its use in `configureClassNode`. 
HotSpot returns declared fields in class-file order — it's the methods array it 
keeps sorted by symbol address, which is why methods and constructors vary and 
fields don't. So sorting fields buys no determinism, and it *costs*: 
`GeneralUtils.getAllProperties` walks `getFields()` in order, so alphabetizing 
a precompiled superclass's fields reorders `@TupleConstructor` parameters. It 
also makes the reflection path disagree with the decompiler path, which 
preserves class-file order.
   
   Constructors, by contrast, live in the methods array as `<init>` and 
genuinely do come back in an arbitrary order — so they belong in the fix 
alongside methods.
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to