codeconsole commented on PR #16323:
URL: https://github.com/apache/grails-core/pull/16323#issuecomment-5593710845

   You're right that it's a breaking change for statically compiled callers — 
that's intentional, and `8.0.x` is the branch where it's allowed. But the 
generic form is worth testing rather than reasoning about, so I ran all three 
signatures against Groovy 5.1.2, each called from `@CompileStatic` code written 
against the old API (`Integer n = api.count()`), with an implementation 
returning `3_000_000_000L`:
   
   | Signature | Result for `Integer n = api.count()` |
   | --- | --- |
   | `<T extends Number> T count()` | **compiles**, returns `-1294967296` |
   | `Long count()` | compile error — `loss of precision from java.lang.Long to 
java.lang.Integer` |
   | `Number count()` | compile error — `Cannot assign value of type 
java.lang.Number to variable of type java.lang.Integer` |
   
   The generic signature does remove the compile error, but it doesn't add 
coercion — it erases to `Object` and lets the call site insert the cast. `T` is 
chosen by the caller, while the implementation can only ever return the one 
type the datastore produced, so the truncation survives and now shows up as a 
negative row count at runtime instead of a build failure. That is the bug this 
PR exists to remove, made invisible. Erasure also means the implementation 
can't inspect `T` and convert to it, so there's no version of that signature 
that could coerce.
   
   `Number` breaks the same callers, so it doesn't avoid the migration either — 
it just hands callers a type they have to unwrap before using.
   
   So there's no non-breaking option here: any type wide enough to hold what 
the datastores actually return is unassignable to `Integer` under STC. Given 
that, the compile error seems like the feature rather than the cost — it points 
at precisely the call sites that were silently truncating, and the fix at each 
is a one-word type change. §54 of the upgrade notes covers the migration, 
including the Java-caller and GraphQL-client cases.
   
   Worth noting where this actually bites: MongoDB aggregates counts with 
`{$sum: 1}`, which returns Int32 and promotes to Int64 once the total exceeds 
it. So on a large collection GORM was receiving the correct 64-bit count and 
`intValue()` was wrapping it — no error, just a wrong number.
   
   Happy to go a different way if you'd still prefer the smaller blast radius.
   


-- 
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