[ 
https://issues.apache.org/jira/browse/GROOVY-11782?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel
 ]

Val E updated GROOVY-11782:
---------------------------
    Description: 
So I ran into a weird optimization bug, where an expected exception gets thrown 
once for an incorrect invocation, will then produce 0 for the exact same 
incorrect invocations, if its followed by a 'correct' invocation. 

 

Attached is a super basic pure java class, with a very basic arithmetic method
{code:java}
package test;

public class JavaTarget {
    public static double primitiveMethod(double value) {
        System.out.println("\tJavaTarget.primitiveMethod v="+value);
        return value - 3.0;
    }
}{code}
The innards of the class are not important, but do note that is take a 
primitive double param and returns a primitive double after subtracting 3 from 
the param

Now when groovy tries to call this class, from a closure, with a Double param, 
we generally expect type coercion, boxing and unboxng, to kick in and 
everything should still work, and it does under normal circumstances. 

However the bug occurs when you call with a Double v= null param, in which case 
type coercion fails, because we cant unbox a null to a double, as expected. If 
you then call it with a good Double, ex Double v=2.0; all subsequent calls with 
Double v=null will be coerced to 0 and no more exception will be thrown.

Test groovy script to illustrate; again vary basic loop 3 times, call java 
target with null and with a 2.0
{code:java}
Closure javaTargetCaller = {Double v ->
    println "\tcall JavaTarget.primitiveMethod($v)"
    JavaTarget.primitiveMethod(v)
}


for(int i = 0; i<3; i++){

    try{
        println "CALL[$i] | with null"
        Object a = javaTargetCaller(null)
        println "\tresult with v=null | *NOT-OK* | expecting exception, got 
"+a+" --"+a.getClass()
    }catch(Exception x){
        println "\tresult with v=null| *OK* |expecting exception, got exception 
--\n"+x
    }

    println "CALL[$i] | with v=-2"
    Object b = javaTargetCaller(-2)
    println "\tresult with v=-2: expecting -5.0 : got "+b
    assert b==-5
}{code}
You will note the first iteration the call will produce an exception as 
expected, however the next call with a param of -2, will cache something in the 
dynamic resolution, and all subsequent calls produce a number, 
{panel:title=Output}
CALL[0] | with null
  call JavaTarget.primitiveMethod(null)
  result with v=null| *OK* |expecting exception, got exception –
  groovy.lang.MissingMethodException: No signature of method: static 
test.JavaTarget.primitiveMethod() is applicable for argument types: (null) 
values: [null]
Possible solutions: primitiveMethod(double)

CALL[0] | with v=-2
  call JavaTarget.primitiveMethod(-2.0)
  JavaTarget.primitiveMethod v=-2.0
  result with v=-2: expecting -5.0 : got -5.0

CALL[1] | with null
  call JavaTarget.primitiveMethod(null)
  JavaTarget.primitiveMethod v=0.0
  result with v=null | *NOT-OK* | expecting exception, got -3.0 --class 
java.lang.Double

CALL[1] | with v=-2
  call JavaTarget.primitiveMethod(-2.0)
  JavaTarget.primitiveMethod v=-2.0
  result with v=-2: expecting -5.0 : got -5.0

CALL[2] | with null
  call JavaTarget.primitiveMethod(null)
  JavaTarget.primitiveMethod v=0.0
  result with v=null | *NOT-OK* | expecting exception, got -3.0 --class 
java.lang.Double

CALL[2] | with v=-2
  call JavaTarget.primitiveMethod(-2.0)
  JavaTarget.primitiveMethod v=-2.0
  result with v=-2: expecting -5.0 : got -5.0
{panel}
-note that the very first call indeed failed to unbox the null and threw an 
exception, however immediately after the second correct call, the nulls start 
getting unboxed to 0 and no more exception get thrown.

-it gets more inconsistent, if you change the order and call with a -2 first, 
then the nulls start getting unboxed to 0 immediately, and no exception is 
thrown ever

Almost like some site call somewhere learns how to unbox a Double null, but it 
depends on the order in which it will be called.

  was:
So I ran into a weird optimization bug, where an expected exception gets thrown 
once for an incorrect invocation, will then produce 0 for the exact same 
incorrect invocations, if its followed by a 'correct' invocation. 

 

Attached is a super basic pure java class, with a very basic arithmetic method


{code:java}
package test;

public class JavaTarget {
    public static double primitiveMethod(double value) {
        System.out.println("\tJavaTarget.primitiveMethod v="+value);
        return value - 3.0;
    }
}{code}
The innards of the class are not important, but do note that is take a 
primitive double param and returns a primitive double after subtracting 3 from 
the param

Now when groovy tries to call this class, from a closure, with a Double param, 
we generally expect type coercion, boxing and unboxng, to kick in and 
everything should still work, and it does under normal circumstances. 

However the bug occurs when you call with a Double v= null param, in which case 
type coercion fails, because we cant unbox a null to a double, as expected. If 
you then call it with a good Double, ex Double v=2.0; all subsequent calls with 
Double v=null will be coerced to 0 and no more exception will be thrown.

Test groovy script to illustrate; again vary basic loop 3 times, call java 
target with null and with a 2.0


{code:java}
Closure javaTargetCaller = {Double v ->
    println "\tcall JavaTarget.primitiveMethod($v)"
    JavaTarget.primitiveMethod(v)
}


for(int i = 0; i<3; i++){

    try{
        println "CALL[$i] | with null"
        Object a = javaTargetCaller(null)
        println "\tresult with v=null | *NOT-OK* | expecting exception, got 
"+a+" --"+a.getClass()
    }catch(Exception x){
        println "\tresult with v=null| *OK* |expecting exception, got exception 
--\n"+x
    }

    println "CALL[$i] | with v=-2"
    Object b = javaTargetCaller(-2)
    println "\tresult with v=-2: expecting -5.0 : got "+b
    assert b==-5
}{code}
You will note the first iteration the call will produce an exception as 
expected, however the next call with a param of -2, will cache something in the 
dynamic resolution, and all subsequent calls produce a number, 


{panel:title=Output}
CALL[0] | with null
  call JavaTarget.primitiveMethod(null)
  result with v=null| *OK* |expecting exception, got exception --
  groovy.lang.MissingMethodException: No signature of method: static 
test.JavaTarget.primitiveMethod() is applicable for argument types: (null) 
values: [null]
Possible solutions: primitiveMethod(double)

CALL[0] | with v=-2
  call JavaTarget.primitiveMethod(-2.0)
  JavaTarget.primitiveMethod v=-2.0
  result with v=-2: expecting -5.0 : got -5.0

CALL[1] | with null
  call JavaTarget.primitiveMethod(null)
  JavaTarget.primitiveMethod v=0.0
  result with v=null | *NOT-OK* | expecting exception, got -3.0 --class 
java.lang.Double

CALL[1] | with v=-2
  call JavaTarget.primitiveMethod(-2.0)
  JavaTarget.primitiveMethod v=-2.0
  result with v=-2: expecting -5.0 : got -5.0

CALL[2] | with null
  call JavaTarget.primitiveMethod(null)
  JavaTarget.primitiveMethod v=0.0
  result with v=null | *NOT-OK* | expecting exception, got -3.0 --class 
java.lang.Double

CALL[2] | with v=-2
  call JavaTarget.primitiveMethod(-2.0)
  JavaTarget.primitiveMethod v=-2.0
  result with v=-2: expecting -5.0 : got -5.0{panel}

-not that the very first call indeed failed to unbox the 0 and threw an 
exception, however immediately after the second correct calls, the nulls start 
getting unboxed to 0 and no more exception get thrown.

-it gets more inconsistent, if you change the order and call with a -2 first, 
then the nulls start getting unboxed to 0, and no exception is thrown ever

Almost like some site call somewhere learns how to unbox a Double null, but it 
depends on the order in which it will be called.


> Inconsistent unboxing of null, and resulting exceptions
> -------------------------------------------------------
>
>                 Key: GROOVY-11782
>                 URL: https://issues.apache.org/jira/browse/GROOVY-11782
>             Project: Groovy
>          Issue Type: Bug
>         Environment: JDK21
> Groovy 4.0.26
>            Reporter: Val E
>            Priority: Minor
>
> So I ran into a weird optimization bug, where an expected exception gets 
> thrown once for an incorrect invocation, will then produce 0 for the exact 
> same incorrect invocations, if its followed by a 'correct' invocation. 
>  
> Attached is a super basic pure java class, with a very basic arithmetic method
> {code:java}
> package test;
> public class JavaTarget {
>     public static double primitiveMethod(double value) {
>         System.out.println("\tJavaTarget.primitiveMethod v="+value);
>         return value - 3.0;
>     }
> }{code}
> The innards of the class are not important, but do note that is take a 
> primitive double param and returns a primitive double after subtracting 3 
> from the param
> Now when groovy tries to call this class, from a closure, with a Double 
> param, we generally expect type coercion, boxing and unboxng, to kick in and 
> everything should still work, and it does under normal circumstances. 
> However the bug occurs when you call with a Double v= null param, in which 
> case type coercion fails, because we cant unbox a null to a double, as 
> expected. If you then call it with a good Double, ex Double v=2.0; all 
> subsequent calls with Double v=null will be coerced to 0 and no more 
> exception will be thrown.
> Test groovy script to illustrate; again vary basic loop 3 times, call java 
> target with null and with a 2.0
> {code:java}
> Closure javaTargetCaller = {Double v ->
>     println "\tcall JavaTarget.primitiveMethod($v)"
>     JavaTarget.primitiveMethod(v)
> }
> for(int i = 0; i<3; i++){
>     try{
>         println "CALL[$i] | with null"
>         Object a = javaTargetCaller(null)
>         println "\tresult with v=null | *NOT-OK* | expecting exception, got 
> "+a+" --"+a.getClass()
>     }catch(Exception x){
>         println "\tresult with v=null| *OK* |expecting exception, got 
> exception --\n"+x
>     }
>     println "CALL[$i] | with v=-2"
>     Object b = javaTargetCaller(-2)
>     println "\tresult with v=-2: expecting -5.0 : got "+b
>     assert b==-5
> }{code}
> You will note the first iteration the call will produce an exception as 
> expected, however the next call with a param of -2, will cache something in 
> the dynamic resolution, and all subsequent calls produce a number, 
> {panel:title=Output}
> CALL[0] | with null
>   call JavaTarget.primitiveMethod(null)
>   result with v=null| *OK* |expecting exception, got exception –
>   groovy.lang.MissingMethodException: No signature of method: static 
> test.JavaTarget.primitiveMethod() is applicable for argument types: (null) 
> values: [null]
> Possible solutions: primitiveMethod(double)
> CALL[0] | with v=-2
>   call JavaTarget.primitiveMethod(-2.0)
>   JavaTarget.primitiveMethod v=-2.0
>   result with v=-2: expecting -5.0 : got -5.0
> CALL[1] | with null
>   call JavaTarget.primitiveMethod(null)
>   JavaTarget.primitiveMethod v=0.0
>   result with v=null | *NOT-OK* | expecting exception, got -3.0 --class 
> java.lang.Double
> CALL[1] | with v=-2
>   call JavaTarget.primitiveMethod(-2.0)
>   JavaTarget.primitiveMethod v=-2.0
>   result with v=-2: expecting -5.0 : got -5.0
> CALL[2] | with null
>   call JavaTarget.primitiveMethod(null)
>   JavaTarget.primitiveMethod v=0.0
>   result with v=null | *NOT-OK* | expecting exception, got -3.0 --class 
> java.lang.Double
> CALL[2] | with v=-2
>   call JavaTarget.primitiveMethod(-2.0)
>   JavaTarget.primitiveMethod v=-2.0
>   result with v=-2: expecting -5.0 : got -5.0
> {panel}
> -note that the very first call indeed failed to unbox the null and threw an 
> exception, however immediately after the second correct call, the nulls start 
> getting unboxed to 0 and no more exception get thrown.
> -it gets more inconsistent, if you change the order and call with a -2 first, 
> then the nulls start getting unboxed to 0 immediately, and no exception is 
> thrown ever
> Almost like some site call somewhere learns how to unbox a Double null, but 
> it depends on the order in which it will be called.



--
This message was sent by Atlassian Jira
(v8.20.10#820010)

Reply via email to