[prev in list] [next in list] [prev in thread] [next in thread]
List: groovy-dev
Subject: [groovy-dev] Is this a bug or a feature: lose lexical scoping when using @CompileDynamic?
From: Brad Miller <brad.l.miller () gmail ! com>
Date: 2014-08-29 12:20:37
Message-ID: CAJRog-DR2-pQUBhtMh1Q2ugJUkdWkJNxT46SSQ_XXA7vnDjKMA () mail ! gmail ! com
[Download RAW message or body]
I hit an issue where I was getting a MissingPropertyException if I used
@CompileDynamic, but the exception went away with @CompileStatic. Below is
a simple test that isolates the behavior, and the underlying issue is how a
read-only private property (via getter) of a parent class is resolved at
runtime by @CompileDynamic versus @CompileStatic.
One possible explanation - it appears that the groovy 'foo' property is
resolved dynamically when using @CompileDynamic, and as the property is
private within the parent class the resolution on the child instance fails
(however, why does getFoo() succeed then?). When @CompileStatic is used,
the normal (java) lexical scoping rules apply, and the parent private
property can be resolved correctly within the parent method.
1. Is this a bug, or an expected difference in behavior for @CompileStatic
/ @CompileDynamic?
2. And is my explanation correct as to what is happening?
3. And how can getFoo() succeed, but 'foo' fail, when using
@CompileDynamic? Shouldn't they always behave the same?
If this is a bug, I'll file a bug report.
Thanks,
Brad
-----------------------------------
Groovy 2.3.4
testCSPrivate succeeds, while second test (testCDPrivate) fails with
following exception on second println statement:
groovy.lang.MissingPropertyException: No such property: foo for class:
myBugReport.bug2.CDChild
at
org.codehaus.groovy.runtime.ScriptBytecodeAdapter.unwrap(ScriptBytecodeAdapter.java:50)
at
org.codehaus.groovy.runtime.callsite.GetEffectivePogoPropertySite.getProperty(GetEffectivePogoPropertySite.java:84)
at
org.codehaus.groovy.runtime.callsite.AbstractCallSite.callGroovyObjectGetProperty(AbstractCallSite.java:231)
at
myBugReport.bug2.CDParent.printWhichAccessesPrivatePropOfParent(CompileDynamicParentPrivateTest.groovy:53)
at
myBugReport.bug2.CDParent$printWhichAccessesPrivatePropOfParent.call(Unknown
Source)
at
org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:45)
at
org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:108)
at
org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:112)
at
myBugReport.bug2.CompileDynamicParentPrivateTest.testCDPrivate(CompileDynamicParentPrivateTest.groovy:22)
-----------------------------------
package myBugReport.bug2
import groovy.transform.CompileDynamic
import groovy.transform.CompileStatic
import org.junit.Test
class CompileDynamicParentPrivateTest
{
// This test SUCCEEDS as CompileStatic parent class can access private
read-only property 'foo'
@Test
public void testCSPrivate()
{
CSChild csChild = new CSChild()
csChild.printWhichAccessesPrivatePropOfParent()
}
// This test FAILS as CompileDynamic parent class can NOT access private
read-only property 'foo'
@Test
public void testCDPrivate()
{
CDChild cdChild = new CDChild()
cdChild.printWhichAccessesPrivatePropOfParent()
}
}
@CompileStatic
class CSParent
{
// Read-only property where only the getter is defined (without a backing
field)
private String getFoo() { return "bar" }
void printWhichAccessesPrivatePropOfParent()
{
System.out.println("Current value of getFoo() is: " + getFoo()) //
works
System.out.println("Current value of foo is: " + foo) // works
with CompileStatic only
}
}
@CompileStatic
class CSChild extends CSParent
{
}
@CompileDynamic
class CDParent
{
// Read-only property where only the getter is defined (without a backing
field)
private String getFoo() { return "bar" }
void printWhichAccessesPrivatePropOfParent()
{
System.out.println("Current value of getFoo() is: " + getFoo()) //
works
System.out.println("Current value of foo is: " + foo) // foo
breaks with CompileDynamic only
}
}
@CompileDynamic
class CDChild extends CDParent
{
}
[Attachment #3 (text/html)]
<div dir="ltr"><div class="gmail_quote"><div dir="ltr">I hit an issue where I was \
getting a MissingPropertyException if I used @CompileDynamic, but the exception went \
away with @CompileStatic. Below is a simple test that isolates the behavior, and \
the underlying issue is how a read-only private property (via getter) of a parent \
class is resolved at runtime by @CompileDynamic versus @CompileStatic.<div>
<br></div><div>One possible explanation - it appears that the groovy 'foo' \
property is resolved dynamically when using @CompileDynamic, and as the property is \
private within the parent class the resolution on the child instance fails (however, \
why does getFoo() succeed then?). When @CompileStatic is used, the normal (java) \
lexical scoping rules apply, and the parent private property can be resolved \
correctly within the parent method.</div>
<div><br></div><div>1. Is this a bug, or an expected difference in behavior for \
@CompileStatic / @CompileDynamic?</div><div>2. And is my explanation correct as to \
what is happening?</div><div>3. And how can getFoo() succeed, but 'foo' fail, \
when using @CompileDynamic? Shouldn't they always behave the same?</div>
<div><br></div><div>If this is a bug, I'll file a bug \
report.</div><div><br></div><div>Thanks,</div><div>Brad</div><div><br></div><div>-----------------------------------</div><div>Groovy \
2.3.4</div><div><br></div><div>
testCSPrivate succeeds, while second test (testCDPrivate) fails with following \
exception on second println statement:</div><blockquote style="margin:0 0 0 \
40px;border:none;padding:0px"><div><div><font face="courier new, \
monospace">groovy.lang.MissingPropertyException: No such property: foo for class: \
myBugReport.bug2.CDChild</font></div>
</div><div><div><font face="courier new, monospace"><span \
style="white-space:pre-wrap"> </span>at \
org.codehaus.groovy.runtime.ScriptBytecodeAdapter.unwrap(ScriptBytecodeAdapter.java:50)</font></div></div><div><div><font \
face="courier new, monospace"><span style="white-space:pre-wrap"> </span>at \
org.codehaus.groovy.runtime.callsite.GetEffectivePogoPropertySite.getProperty(GetEffectivePogoPropertySite.java:84)</font></div>
</div><div><div><font face="courier new, monospace"><span \
style="white-space:pre-wrap"> </span>at \
org.codehaus.groovy.runtime.callsite.AbstractCallSite.callGroovyObjectGetProperty(AbstractCallSite.java:231)</font></div></div>
<div><div><font face="courier new, monospace"><span \
style="white-space:pre-wrap"> </span>at \
myBugReport.bug2.CDParent.printWhichAccessesPrivatePropOfParent(CompileDynamicParentPrivateTest.groovy:53)</font></div>
</div><div><div><font face="courier new, monospace"><span \
style="white-space:pre-wrap"> </span>at \
myBugReport.bug2.CDParent$printWhichAccessesPrivatePropOfParent.call(Unknown \
Source)</font></div></div><div><div><font face="courier new, monospace"><span \
style="white-space:pre-wrap"> </span>at \
org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:45)</font></div>
</div><div><div><font face="courier new, monospace"><span \
style="white-space:pre-wrap"> </span>at \
org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:108)</font></div></div><div><div><font \
face="courier new, monospace"><span style="white-space:pre-wrap"> </span>at \
org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:112)</font></div>
</div><div><div><font face="courier new, monospace"><span \
style="white-space:pre-wrap"> </span>at \
myBugReport.bug2.CompileDynamicParentPrivateTest.testCDPrivate(CompileDynamicParentPrivateTest.groovy:22)</font></div></div>
</blockquote><div><div><br></div></div>
<div><br></div><div>-----------------------------------</div><font face="courier new, \
monospace">package myBugReport.bug2<br><br>import \
groovy.transform.CompileDynamic<br>import groovy.transform.CompileStatic<br>import \
org.junit.Test<br> <br>class CompileDynamicParentPrivateTest<br>
{<br> // This test SUCCEEDS as CompileStatic parent class can access private \
read-only property 'foo'<br> @Test<br> public void testCSPrivate()<br> \
{<br> CSChild csChild = new CSChild()<br> \
csChild.printWhichAccessesPrivatePropOfParent()<br>
}<br><br> // This test FAILS as CompileDynamic parent class can NOT access \
private read-only property 'foo'<br> @Test<br> public void \
testCDPrivate()<br> {<br> CDChild cdChild = new CDChild()<br> \
cdChild.printWhichAccessesPrivatePropOfParent()<br>
}<br>}<br><br>@CompileStatic<br>class CSParent<br>{<br> // Read-only property \
where only the getter is defined (without a backing field)<br> private String \
getFoo() { return "bar" }<br><br> void \
printWhichAccessesPrivatePropOfParent()<br>
{<br> System.out.println("Current value of getFoo() is: " + \
getFoo()) // works<br> System.out.println("Current value of foo is: \
" + foo) // works with CompileStatic only<br> }<br>}<br>
<br>@CompileStatic<br>class CSChild extends \
CSParent<br>{<br>}<br><br>@CompileDynamic<br>class CDParent<br>{<br> // Read-only \
property where only the getter is defined (without a backing field)<br> private \
String getFoo() { return "bar" }<br>
<br> void printWhichAccessesPrivatePropOfParent()<br> {<br> \
System.out.println("Current value of getFoo() is: " + getFoo()) // \
works<br> System.out.println("Current value of foo is: " + foo) \
// foo breaks with CompileDynamic only<br>
}<br>}<br><br>@CompileDynamic<br>class CDChild extends \
CDParent<br>{<br>}</font></div> </div><br></div>
[prev in list] [next in list] [prev in thread] [next in thread]
Configure |
About |
News |
Add a list |
Sponsored by KoreLogic