Rachel Greenham created GROOVY-10099:
----------------------------------------

             Summary: A single null argument to a varargs parameter is received 
as null
                 Key: GROOVY-10099
                 URL: https://issues.apache.org/jira/browse/GROOVY-10099
             Project: Groovy
          Issue Type: Bug
         Environment: Observed on Groovy 3.0.8 on macOS Big Sur (Intel), but I 
don't think that's relevant; it'll be everywhere.
            Reporter: Rachel Greenham
         Attachments: VarArgsTest.groovy, VarArgsTest.jsh

(NB: I would set the priority to P2 default to be triaged, but I seem not to 
have that option, so I left it at the default I was presented with.)

When calling a method with a varargs parameter with a single value, that value 
is wrapped into an array of length 1. This is the behaviour in Java, and is the 
expected behaviour, and _most_ of the time is the behaviour in Groovy too.

But when that single value is null, Groovy will instead just pass the null into 
the method. Java will not do this: You'll get an array with a single null in 
it. Because Groovy's behaviour is unexpected, especially when interfacing with 
Java code, NullPointerExceptions can often ensue.

Adding to the inconsistencies, if the Groovy code calling the method is in a 
{{@CompileStatic}} context, it behaves just like Java, and the method (whether 
or not _it_ is statically compiled or a dynamic Groovy method) receives an 
array with a null in it.

So the behaviour in Groovy is inconsistent, both with itself in a 
{{@CompileStatic}} situation, and with Java, and is requiring workarounds in 
Java code to handle this normally-impossible eventuality. (Even if no varargs 
parameter is given you get an empty array, as in fact you do in Groovy too.)

This may be an "early instalment weirdness": There's an ancient ticket, from 
not long after varargs were introduced into Java, which appears to have argued 
- successfully at the time - that the normal behaviour is a bug: 
https://issues.apache.org/jira/browse/GROOVY-1026 

Further adding to the confusion may be that Groovy usually elides the 
difference between an {{Object[]}} parameter and an {{Object...}} parameter: 
They both behave the same.

The offending code appears to be in 
org.codehaus.groovy.reflection.ParameterTypes.java in method fitToVars, lines 
200-215 in master at the time of writing, which even includes a comment that 
"if the last argument is null, then we don't have to do anything", with which I 
respectfully disagree. :) That behaviour should be to return an array with a 
single null in it (Handily, MetaClassHelper.ARRAY_WITH_NULL saves having to 
make a new one.)

In principle it's an easy fix (although I've left tagging to others as this is 
my first issue here), but there'd be an obvious nervousness about changing 
behaviour like this when there might be a lot of old code out there depending 
on it behaving the way it does now. OTOH the way it behaves now is breaking the 
expectations of those of us coming to Groovy from a lifetime of Java...

Attachments:

VarArgsTest.groovy - a script saved from, and runnable in, groovyConsole, 
demonstrating the behaviour. The behaviour is the same regardless of whether 
the console is launched with the --indy option. (The issue was initially 
observed in indy.) The dynamic portion of the test, when run, ends in a 
NullPointerException as Arrays.asList is not expecting a null varargs 
parameter. Output seen (--indy or  not):

 
{code:java}
name: the static name 1
params is null? false
params length is 1
[blah]
name: the static name 2
params is null? false
params length is 2[blah, blue]
name: the static name 3 with blah=null
params is null? false
params length is 1
[null]
Arrays.asList(blah)? [null]

name: the dynamic name 1
params is null? false
params length is 1
[blah]
name: the dynamic name 2
params is null? false
params length is 2[blah, blue]
name: the dynamic name 3 with blah=null
params is null? true
Exception thrown

java.lang.NullPointerException
...{code}
(etc. stack trace not shown for formatting reasons.)

VarArgsTest.jsh - a jshell script demonstrating Java's behaviour, very similar 
to the groovy test, but omitting the dynamic portion of the test for obvious 
reasons. (The statements in the Groovy script ending in semicolons are left 
that way precisely to mark that they're identical to the Java test.) Runnable 
with

 
{code:java}
jshell PRINTING VarArgsTest.jsh
{code}
Output seen:
{code:java}
name: the static name 1
params is null? false
params length is 1
[blah]
name: the static name 2
params is null? false
params length is 2
[blah, blue]
name: the static name 3 with blah=null
params is null? false
params length is 1
[null]
Arrays.asList(blah)? [null]
{code}



--
This message was sent by Atlassian Jira
(v8.3.4#803005)

Reply via email to