[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 &#39;foo&#39; \
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 &#39;foo&#39; fail, \
when using @CompileDynamic?   Shouldn&#39;t they always behave the same?</div>

<div><br></div><div>If this is a bug, I&#39;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 &#39;foo&#39;<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 &#39;foo&#39;<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 &quot;bar&quot; }<br><br>   void \
printWhichAccessesPrivatePropOfParent()<br>

   {<br>      System.out.println(&quot;Current value of getFoo() is: &quot; + \
getFoo())      // works<br>      System.out.println(&quot;Current value of foo is: \
&quot; + 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 &quot;bar&quot; }<br>

<br>   void printWhichAccessesPrivatePropOfParent()<br>   {<br>      \
System.out.println(&quot;Current value of getFoo() is: &quot; + getFoo())      // \
works<br>      System.out.println(&quot;Current value of foo is: &quot; + 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