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

Scott Murphy Heiberg updated GROOVY-12578:
------------------------------------------
    Description: 
For an implicit-this call in a closure body to a method the closure inherits, 
such as {{toString()}} or a default Groovy method like {{with}}, {{tap}} or 
{{identity}}, {{ClosureMetaClass}} tries the delegate and the owner first and 
keeps the closure's own method as the fallback. When neither can take the call, 
it invokes the fallback, discards the result and throws 
{{MissingMethodException}}; invokedynamic catches it and calls the method again 
through {{GroovyObject.invokeMethod}}, so the method runs twice:

{code:groovy}
class C { Closure<Integer> withCount() { { -> int n = 0; with { n++ }; n } } }
Closure<Integer> c = new C().withCount().rehydrate(null, null, null)
c.resolveStrategy = Closure.OWNER_ONLY
assert c() == 1 // 2
{code}

Called through the meta class directly ({{c.metaClass.invokeMethod(...)}}), the 
call throws {{MissingMethodException}} after running the method. A closure 
without an owner and with {{OWNER_ONLY}}, or with {{DELEGATE_ONLY}} and no 
delegate, reaches the fallback. Expected: the fallback's result is returned.

PR: https://github.com/apache/groovy/pull/3104

  was:
For an implicit-this call in a closure body to a method the closure inherits, 
such as {{toString()}} or a default Groovy method like {{with}}, {{tap}} or 
{{identity}}, {{ClosureMetaClass}} tries the delegate and the owner first and 
keeps the closure's own method as the fallback. When neither can take the call, 
it invokes the fallback, discards the result and throws 
{{MissingMethodException}}; invokedynamic catches it and calls the method again 
through {{GroovyObject.invokeMethod}}, so the method runs twice:

{code:groovy}
class C { Closure<Integer> withCount() { { -> int n = 0; with { n++ }; n } } }
Closure<Integer> c = new C().withCount().rehydrate(null, null, null)
c.resolveStrategy = Closure.OWNER_ONLY
assert c() == 1 // 2
{code}

Called through the meta class directly ({{c.metaClass.invokeMethod(...)}}), the 
call throws {{MissingMethodException}} after running the method. A closure 
without an owner and with {{OWNER_ONLY}}, or with {{DELEGATE_ONLY}} and no 
delegate, reaches the fallback. Expected: the fallback's result is returned.


> A closure's own method runs twice when neither the delegate nor the owner can 
> take the call
> -------------------------------------------------------------------------------------------
>
>                 Key: GROOVY-12578
>                 URL: https://issues.apache.org/jira/browse/GROOVY-12578
>             Project: Groovy
>          Issue Type: Bug
>          Components: groovy-runtime
>    Affects Versions: 6.0.0
>            Reporter: Scott Murphy Heiberg
>            Priority: Major
>
> For an implicit-this call in a closure body to a method the closure inherits, 
> such as {{toString()}} or a default Groovy method like {{with}}, {{tap}} or 
> {{identity}}, {{ClosureMetaClass}} tries the delegate and the owner first and 
> keeps the closure's own method as the fallback. When neither can take the 
> call, it invokes the fallback, discards the result and throws 
> {{MissingMethodException}}; invokedynamic catches it and calls the method 
> again through {{GroovyObject.invokeMethod}}, so the method runs twice:
> {code:groovy}
> class C { Closure<Integer> withCount() { { -> int n = 0; with { n++ }; n } } }
> Closure<Integer> c = new C().withCount().rehydrate(null, null, null)
> c.resolveStrategy = Closure.OWNER_ONLY
> assert c() == 1 // 2
> {code}
> Called through the meta class directly ({{c.metaClass.invokeMethod(...)}}), 
> the call throws {{MissingMethodException}} after running the method. A 
> closure without an owner and with {{OWNER_ONLY}}, or with {{DELEGATE_ONLY}} 
> and no delegate, reaches the fallback. Expected: the fallback's result is 
> returned.
> PR: https://github.com/apache/groovy/pull/3104



--
This message was sent by Atlassian Jira
(v10.3.26#10030026)

Reply via email to