[jira] [Commented] (GROOVY-8660) Unexpected MethodSelectionException with implicit null argument

2021-11-19 Thread Jochen Theodorou (Jira)


[ 
https://issues.apache.org/jira/browse/GROOVY-8660?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel=17446767#comment-17446767
 ] 

Jochen Theodorou commented on GROOVY-8660:
--

I just happen to find this by chance. The mechanism for foo() calling foo(x) is 
an eyesore to me for a long time. Yes I wanted to remove it and most people 
agreed with it, though it is difficult to know if these know the implications 
to existing code. Anyway...

RULE1:  For varargs and calling foo(SomeClass...) we basically have the 
following rules from Java:

# *foo( )* -> calls foo with empty array of type SomeClass[]
# *foo( null )* -> calls foo with null
# *foo( x )* -> calls foo using the reference provided by x is x is an array 
and its element type is a subclass of SomeClass. Otherwise the method is not 
applicable
# *foo( y_1, y_2, ..., y_n )* -> calls foo wrapping all y_i in an array if all 
the y_i are a subclass of SomeClass. The Array will have the class SomeClass[].

RULE2: For the... let me call it null-expansion we have the following rule:
If normal method selection fails and the call is without arguments try method 
selection again with null as argument. In the method distance algorithm any 
expansion, that has to be made gives a distance penalty. That means a 
foo(someClass...) has a bigger distance for a call foo() than if I would call a 
method declared as foo() directly.  foo(null) or foo(x) do not have that 
penalty, because no additional action has to be taken.

Now let's look at the cases in the issue:
{code:Java}
class OnlySingle {
def foo(a) { "single param: $a" }
}

println new OnlySingle().foo()
// as expected: 'single param: null'
{code}
This means the initial method selection fails and we start a second method 
selection with foo(null), which then successfully calls the method. RULE1
{code:Java}
class Both {
def foo(a) { "single param: $a" }
def foo(a, ... b) { "vararg param: $a, $b" }
}

println new Both().foo()
// unexpected:
// MethodSelectionException: Could not find which method foo() to invoke from 
this list:
//  public java.lang.Object Both#foo(java.lang.Object)
//  public transient java.lang.Object Both#foo(java.lang.Object, 
[Ljava.lang.Object;)
{code}
Here actually the first method selection fails, since there is no applicable 
method without argument. Because of RULE2 we then try foo(null). And unlike the 
optimization done, this was supposed to be a full method selection. That means 
we are looking at foo(Object) and foo(Object,Object...) to select from. Because 
of RULE1 foo(Object,Object...) has a penalty compared to foo(Object), as we 
need to do an expansion to fit the varargs call.

This means a correct implementation should not throw an MSE, it should have 
selected foo(Object) with null as argument.



> Unexpected MethodSelectionException with implicit null argument
> ---
>
> Key: GROOVY-8660
> URL: https://issues.apache.org/jira/browse/GROOVY-8660
> Project: Groovy
>  Issue Type: Bug
>Affects Versions: 3.0.0-alpha-2, 2.4.15, 2.5.0
>Reporter: Daniil Ovchinnikov
>Priority: Major
>  Labels: varargs
>
> {code:groovy}
> class OnlySingle {
> def foo(a) { "single param: $a" }
> }
> println new OnlySingle().foo()
> // as expected: 'single param: null'
> class OnlyVararg {
> def foo(a, ... b) { "vararg param: $a, $b" }
> }
> println new OnlyVararg().foo()
> // as expected: 'MME: No signature of method: OnlyVararg.foo() is applicable 
> for argument types: () values: []'
> class Both {
> def foo(a) { "single param: $a" }
> def foo(a, ... b) { "vararg param: $a, $b" }
> }
> println new Both().foo()
> // unexpected:
> // MethodSelectionException: Could not find which method foo() to invoke from 
> this list:
> //  public java.lang.Object Both#foo(java.lang.Object)
> //  public transient java.lang.Object Both#foo(java.lang.Object, 
> [Ljava.lang.Object;)
> {code}
> If the exception is expected then {{OnlyVararg}} case should work too.
> If the exception is unexpected then {{Both#foo(Object)}} should be selected.



--
This message was sent by Atlassian Jira
(v8.20.1#820001)


[jira] [Commented] (GROOVY-8660) Unexpected MethodSelectionException with implicit null argument

2021-06-16 Thread Paul King (Jira)


[ 
https://issues.apache.org/jira/browse/GROOVY-8660?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel=17364329#comment-17364329
 ] 

Paul King commented on GROOVY-8660:
---

[~blackdrag], you don't recall any more specifics do you? Otherwise I can try 
to refresh my memory by trawling through the mailing lists or commit history.

> Unexpected MethodSelectionException with implicit null argument
> ---
>
> Key: GROOVY-8660
> URL: https://issues.apache.org/jira/browse/GROOVY-8660
> Project: Groovy
>  Issue Type: Bug
>Affects Versions: 3.0.0-alpha-2, 2.4.15, 2.5.0
>Reporter: Daniil Ovchinnikov
>Priority: Major
>
> {code:groovy}
> class OnlySingle {
> def foo(a) { "single param: $a" }
> }
> println new OnlySingle().foo()
> // as expected: 'single param: null'
> class OnlyVararg {
> def foo(a, ... b) { "vararg param: $a, $b" }
> }
> println new OnlyVararg().foo()
> // as expected: 'MME: No signature of method: OnlyVararg.foo() is applicable 
> for argument types: () values: []'
> class Both {
> def foo(a) { "single param: $a" }
> def foo(a, ... b) { "vararg param: $a, $b" }
> }
> println new Both().foo()
> // unexpected:
> // MethodSelectionException: Could not find which method foo() to invoke from 
> this list:
> //  public java.lang.Object Both#foo(java.lang.Object)
> //  public transient java.lang.Object Both#foo(java.lang.Object, 
> [Ljava.lang.Object;)
> {code}
> If the exception is expected then {{OnlyVararg}} case should work too.
> If the exception is unexpected then {{Both#foo(Object)}} should be selected.



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


[jira] [Commented] (GROOVY-8660) Unexpected MethodSelectionException with implicit null argument

2021-06-16 Thread Eric Milles (Jira)


[ 
https://issues.apache.org/jira/browse/GROOVY-8660?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel=17364325#comment-17364325
 ] 

Eric Milles commented on GROOVY-8660:
-

I only found out about this a couple weeks ago.  As best as I can gather, the 
method selection (in MetaClassImpl) will translate "foo()" to "foo(null)" if 
there is only one method "foo" for the receiver type and the method has one 
non-primitive parameter.  This extends to category methods, so a static 
category method will apply to "foo()" if is has one self parameter and one 
additional non-primitive parameter.

In your "Both" case, the one method criterion is not met.  I'm not sure why 
this exists and I think I have seen some discussion of removing it in MOP 2.0.  
But I think that effort is largely stalled.

> Unexpected MethodSelectionException with implicit null argument
> ---
>
> Key: GROOVY-8660
> URL: https://issues.apache.org/jira/browse/GROOVY-8660
> Project: Groovy
>  Issue Type: Bug
>Affects Versions: 3.0.0-alpha-2, 2.4.15, 2.5.0
>Reporter: Daniil Ovchinnikov
>Priority: Major
>
> {code:groovy}
> class OnlySingle {
> def foo(a) { "single param: $a" }
> }
> println new OnlySingle().foo()
> // as expected: 'single param: null'
> class OnlyVararg {
> def foo(a, ... b) { "vararg param: $a, $b" }
> }
> println new OnlyVararg().foo()
> // as expected: 'MME: No signature of method: OnlyVararg.foo() is applicable 
> for argument types: () values: []'
> class Both {
> def foo(a) { "single param: $a" }
> def foo(a, ... b) { "vararg param: $a, $b" }
> }
> println new Both().foo()
> // unexpected:
> // MethodSelectionException: Could not find which method foo() to invoke from 
> this list:
> //  public java.lang.Object Both#foo(java.lang.Object)
> //  public transient java.lang.Object Both#foo(java.lang.Object, 
> [Ljava.lang.Object;)
> {code}
> If the exception is expected then {{OnlyVararg}} case should work too.
> If the exception is unexpected then {{Both#foo(Object)}} should be selected.



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


[jira] [Commented] (GROOVY-8660) Unexpected MethodSelectionException with implicit null argument

2021-06-16 Thread Daniil Ovchinnikov (Jira)


[ 
https://issues.apache.org/jira/browse/GROOVY-8660?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel=17364269#comment-17364269
 ] 

Daniil Ovchinnikov commented on GROOVY-8660:


This should be documented somewhere. Last time I've checked, there was 
something like: "if a method can be called with a single null argument, then 
the argument can be omitted", there was no mention that the method must not 
have overloads or varargs. 

If {{new OnlyVararg().foo()}} fails
=> {{Both#foo(Object, [LObject;)}} must be inapplicable
=>  method selection in {{new Both().foo()}} should try only 
{{Both#foo(Object)}} against {{null}} argument 
=> {{Both#foo(Object)}} should be selected.

Now let's reverse the above.

If {{Both#foo(Object)}} is not selected
=> method selection in {{new Both().foo()}} actually sees both methods as 
applicable before trying them with null argument
=> {{Both#foo(Object, [LObject;)}} was applicable
=> {{new OnlyVararg().foo()}} must not fail.

I'm having trouble understanding `org.codehaus.groovy.*` code. Can you describe 
me the algorithm in human words, please?

> Unexpected MethodSelectionException with implicit null argument
> ---
>
> Key: GROOVY-8660
> URL: https://issues.apache.org/jira/browse/GROOVY-8660
> Project: Groovy
>  Issue Type: Bug
>Affects Versions: 3.0.0-alpha-2, 2.4.15, 2.5.0
>Reporter: Daniil Ovchinnikov
>Priority: Major
>
> {code:groovy}
> class OnlySingle {
> def foo(a) { "single param: $a" }
> }
> println new OnlySingle().foo()
> // as expected: 'single param: null'
> class OnlyVararg {
> def foo(a, ... b) { "vararg param: $a, $b" }
> }
> println new OnlyVararg().foo()
> // as expected: 'MME: No signature of method: OnlyVararg.foo() is applicable 
> for argument types: () values: []'
> class Both {
> def foo(a) { "single param: $a" }
> def foo(a, ... b) { "vararg param: $a, $b" }
> }
> println new Both().foo()
> // unexpected:
> // MethodSelectionException: Could not find which method foo() to invoke from 
> this list:
> //  public java.lang.Object Both#foo(java.lang.Object)
> //  public transient java.lang.Object Both#foo(java.lang.Object, 
> [Ljava.lang.Object;)
> {code}
> If the exception is expected then {{OnlyVararg}} case should work too.
> If the exception is unexpected then {{Both#foo(Object)}} should be selected.



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


[jira] [Commented] (GROOVY-8660) Unexpected MethodSelectionException with implicit null argument

2021-06-15 Thread Eric Milles (Jira)


[ 
https://issues.apache.org/jira/browse/GROOVY-8660?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel=17363714#comment-17363714
 ] 

Eric Milles commented on GROOVY-8660:
-

That said, I think the method selection is working as intended.  Are you 
looking for a change in one of the cases?

> Unexpected MethodSelectionException with implicit null argument
> ---
>
> Key: GROOVY-8660
> URL: https://issues.apache.org/jira/browse/GROOVY-8660
> Project: Groovy
>  Issue Type: Bug
>Affects Versions: 3.0.0-alpha-2, 2.4.15, 2.5.0
>Reporter: Daniil Ovchinnikov
>Priority: Major
>
> {code:groovy}
> class OnlySingle {
> def foo(a) { "single param: $a" }
> }
> println new OnlySingle().foo()
> // as expected: 'single param: null'
> class OnlyVararg {
> def foo(a, ... b) { "vararg param: $a, $b" }
> }
> println new OnlyVararg().foo()
> // as expected: 'MME: No signature of method: OnlyVararg.foo() is applicable 
> for argument types: () values: []'
> class Both {
> def foo(a) { "single param: $a" }
> def foo(a, ... b) { "vararg param: $a, $b" }
> }
> println new Both().foo()
> // unexpected:
> // MethodSelectionException: Could not find which method foo() to invoke from 
> this list:
> //  public java.lang.Object Both#foo(java.lang.Object)
> //  public transient java.lang.Object Both#foo(java.lang.Object, 
> [Ljava.lang.Object;)
> {code}
> If the exception is expected then {{OnlyVararg}} case should work too.
> If the exception is unexpected then {{Both#foo(Object)}} should be selected.



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


[jira] [Commented] (GROOVY-8660) Unexpected MethodSelectionException with implicit null argument

2021-06-15 Thread Eric Milles (Jira)


[ 
https://issues.apache.org/jira/browse/GROOVY-8660?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel=17363712#comment-17363712
 ] 

Eric Milles commented on GROOVY-8660:
-

The implicit null selection only works when there is a single method with one 
non-primitive parameter.  It is the last case in 
{{org.codehaus.groovy.reflection.ParameterTypes#isValidMethod}}:
{code:java}
public boolean isValidMethod(Class[] arguments) {
if (arguments == null) return true;
final int size = arguments.length;
CachedClass[] pt = getParameterTypes();
final int paramMinus1 = pt.length - 1;
if (isVargsMethod && size >= paramMinus1)
return isValidVarargsMethod(arguments, size, pt, paramMinus1);
else if (pt.length == size)
return isValidExactMethod(arguments, pt);
else if (pt.length == 1 && size == 0 && !pt[0].isPrimitive) // here
return true;
return false;
}
{code}

When there are multiple methods available and no arguments, selection goes 
through {{MetaClassHelper.chooseEmptyMethodParams}} in 
{{groovy.lang.MetaClassImpl#chooseMethodInternal}}, which just tries to execute 
a no-arg method instead of a varargs method if both are declared.

> Unexpected MethodSelectionException with implicit null argument
> ---
>
> Key: GROOVY-8660
> URL: https://issues.apache.org/jira/browse/GROOVY-8660
> Project: Groovy
>  Issue Type: Bug
>Affects Versions: 3.0.0-alpha-2, 2.4.15, 2.5.0
>Reporter: Daniil Ovchinnikov
>Priority: Major
>
> {code:groovy}
> class OnlySingle {
> def foo(a) { "single param: $a" }
> }
> println new OnlySingle().foo()
> // as expected: 'single param: null'
> class OnlyVararg {
> def foo(a, ... b) { "vararg param: $a, $b" }
> }
> println new OnlyVararg().foo()
> // as expected: 'MME: No signature of method: OnlyVararg.foo() is applicable 
> for argument types: () values: []'
> class Both {
> def foo(a) { "single param: $a" }
> def foo(a, ... b) { "vararg param: $a, $b" }
> }
> println new Both().foo()
> // unexpected:
> // MethodSelectionException: Could not find which method foo() to invoke from 
> this list:
> //  public java.lang.Object Both#foo(java.lang.Object)
> //  public transient java.lang.Object Both#foo(java.lang.Object, 
> [Ljava.lang.Object;)
> {code}
> If the exception is expected then {{OnlyVararg}} case should work too.
> If the exception is unexpected then {{Both#foo(Object)}} should be selected.



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