1. Ok, I had a bit of time to play around with this some more, and
found that it works in principle if I cast the NULL_TO macro result
to the "type of the input expressions".
2. To find the type to cast to I currently do a find over the
Expression[] until I get the Expression#type is != Object-class-node.
3. That works inside a test, where I do e.g.:
final BigDecimal bd = NULL_TO(null, null, new BigDecimal(123.456),
neverCalled())
4. ...but unfortunately it does not in the real world, where
the NULL_TO parameters are often method parameters of the
surrounding method - and their Expression#type alas seems always to
be Object (?)
5. Question: How do I get the actual type of method parameters as given
in the source code (hope they have not been erased at this point,
since then I would be back to square one...) ?
1. e.g. (nonsensical, just to show the problem):
void foo(BigDecimal x0, BigDecimal x1) {
final BigDecimal x = NULL_TO(x0, x1) // still fails with
"cannot assign Object to BigDecimal", since the Expression#type
of the x0 and x1 Expression|s is a class node of type
java.lang.Object...
}
6. Bonus question: What one evidently would want is not the type of one
of the Expression|s passed to NULL_TO, but instead the common
supertype of all the Expression|s - is there any accessible existing
functionality to get that ?-)
Cheers,
mg
Am 22.09.2026 um 21:01 schrieb MG:
Hi guys,
first, congrats on Groovy 6.0.0 G-)
We are still on Groovy 4 (kind of dreading what IntelliJ Intellisense
will do with a newer Groovy version, given how much code it
incorrectly marks as "erronous" now), and I finally found the time to
do a quick spike to create an early-out null-mapping macro, which
tests only for !== null (no Groovy truth, because in 99% of cases that
is not what we want) and takes an arbitrary number of arguments:
Examples:
final x = NULL_TO(x0(),x1(),x2(),x3(),x4()) // same as ternary/Elvis
operator, x1(),etc is only evaluated, if x0() evaluates to null, etc
final sqe = NULL_TO(sqlExecutorIn, Global.sqe, createSqlExecutor()) //
again, createSqlExecutor() is only called iff sqlExecutorIn and
Global.sqe are both null
Macro stub:
static <T> T NULL_TO(T... args) { ... }
This works fine, the only problem is, that under static compilation
the resulting return type of NULL_TO always seems to be Object
(instead of generic type T), so I have to use an explicit type cast in
these cases, which is decidedly un-Groovy.
Examples:
// If x0(), etc all have return type BigDecimal, fails later on when
trying to use BigDecimal functionality on x under @CompileStatic
without the cast
final x = (BigDecimal) NULL_TO(x0(),x1(),x2(),x3(),x4())
// Fails with "Object cannot be assigned to SqlExecutor" under
@CompileStatic otherwise
final SqlExecutor sqe = (SqlExecutor) NULL_TO(sqlExecutorIn,
Global.sqe, createSqlExecutor())
Comparing this to the existing named value macros, it seems return
types only work if they are given explicitly, but not when they are
generics... (?)
Is there a way to fix/improve this and avoid the cast (or equivalent
"as ...") ? Was this improved in newer Grooyv versions (I searched the
Groovy Jira, but found nothing in the very small number of tickets
that has "macro" in their summary) ?
Thanks, cheers,
mg