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

Eric Milles updated GROOVY-11367:
---------------------------------
    Description: 
The rules for property read and write for map-based types still have several 
inconsistencies:
{code:groovy}
class M extends HashMap<String,Object> {
  public pub
  protected pro
  @PackageScope pack
  private priv
  def prop
  def getAny() {}
  void setAny(value) {}
}
{code}
 # Read and write do not share a consistent resolution order – noted in 8555. 
Should access method selection take visibility into account? I think sender 
information is not always available to {{MetaClassImpl}} so the "inside class" 
behavior is required.
{code:groovy}
void test1(M map) {
  map.pub  // field (fixed in 5001)
  map.pro  // entry
  map.pack // entry
  map.priv // entry
  map.prop // property (fixed in 5001)
  map.any  // getter (all visibilities -- fixed in 5001) or entry for subclass 
of M (private or package-private other-package subclass -- fixed in 11357)
  map.empty // entry ("class" and "metaClass" as well)

  map.pub  = null // field
  map.pro  = null // field
  map.pack = null // entry
  map.priv = null // entry
  map.prop = null // property
  map.any  = null // setter (all visibilities) or entry for subclass of M 
(private or package-private other-package subclass -- fixed in 11357)
  map.empty = null // entry
  map.class = null // entry
  map.metaClass = null // setter via 
ScriptBytecodeAdapter#setGroovyObjectProperty
}
{code}
 # "this" and "super" have different behavior.
{code:groovy}
  // add this to the body of M
  void test2(M that) {
    this.pub  // field
    this.pro  // field
    this.pack // field
    this.priv // field
    this.prop // property
    this.any  // getter (all visibilities -- fixed in 5001)
    this.class // entry (dynamic) or isser (static)
    this.empty // entry or getter (static)
    this.metaClass // field (dynamic) or getter (static)

    this.pub = null // field (same for "pro", "pack", "priv" and "prop")
    this.any = null // setter (all visibilities) or entry for subclass of M 
(private or package-private other-package subclass -- fixed in 11357)
    this.empty = null // entry (dynamic) or error (static)
    this.class = null // entry (dynamic) or error (static)
    this.metaClass = null // field (dynamic) or setter (static)

    def that = this
    that.* // see test1 (except "empty", "class" and "metaClass")
    that.empty // entry (dynamic) or isser (static)
    that.class // entry (dynamic) or getter (static)
    that.metaClass // entry (dynamic) or getter (static)
  }
{code}
 # Dynamic and static compilation have different behavior.
{code:groovy}
@groovy.transform.CompileStatic
void test3(M map) {
  map.pub  // field (changed in 5001/5491)
  map.pro  // field (changed in 5001/5491: in package or subclass) or entry
  map.pack // field (changed in 5001/5491: in package)             or entry
  map.priv // entry
  map.prop // property (changed in 5001/5491)
  map.any  // getter (accessible -- changed in 5001/5491) or entry 
(inaccessible)
  map.empty // isser (changed in 5001/5491)
  map.class // getter (changed in 5001/5491)
  map.metaClass // getter (changed in 5001/5491)

  map.pub  = null // entry (changed in 6954) or field (fixed in 11376)
  map.pro  = null // entry (changed in 6954) or field (fixed in 11376)
  map.pack = null // entry
  map.priv = null // entry
  map.prop = null // property
  map.any  = null // setter (accessible) or error (inaccessible)
  map.empty = null // error "Cannot set read-only property: empty" (and 
"class") -- GROOVY-11369
  map.metaClass = null // setter via DefaultGroovyMethods#setMetaClass
}
{code}
 # Closures intercept some properties.
{code:groovy}
void test4(M map) {
  map.with {
    pub // field
    pro // entry
    pack // entry
    priv // entry
    prop // property
    directive // closure property
    metaClass // closure property (and so on for "owner", "delegate", 
"thisObject", ...)
  }
}
{code}
 # The rules change a bit for fields declared by super class.
{code:groovy}
class MM extends M {
  void test5() {
    this.pub   // field (fixed in 5001)
    this.pro   // entry
    this.pack  // entry
    this.priv  // entry
    this.prop  // property (fixed in 5001)
    this.any   // getter (public, protected, package-private if same-package) 
or entry (private, package-private if other-package)
    this.class // entry
    this.empty // entry
    this.metaClass // entry

    this.pub  = null // field
    this.pro  = null // field
    this.pack = null // entry
    this.priv = null // entry
    this.prop = null // property
    this.any  = null // setter (public, protected, package-private if 
same-package) or entry (private, package-private if other-package -- fixed in 
11357)
    this.empty = null // entry
    this.class = null // entry
    this.metaClass = null // setter via 
ScriptBytecodeAdapter#setGroovyObjectProperty
  }
}
{code}
# Calling a name bypasses map lookup.
{code:groovy}
void test6(M map) {
  map.pack() // field read and call
  map.priv() // field read and call
}
{code}

GROOVY-662, GROOVY-5001, GROOVY-5491, GROOVY-5517, GROOVY-5985, GROOVY-6144, 
GROOVY-6277, GROOVY-6954, GROOVY-8065, GROOVY-8074, GROOVY-8265, GROOVY-8555, 
GROOVY-8978, GROOVY-9127, GROOVY-11144, GROOVY-11319, GROOVY-11223, 
GROOVY-11357, GROOVY-11360, GROOVY-11368, GROOVY-11369, GROOVY-11370, 
GROOVY-11376 GROOVY-11384, GROOVY-11386, GROOVY-11387, GROOVY-11390, 
GROOVY-11401

  was:
The rules for property read and write for map-based types still have several 
inconsistencies:
{code:groovy}
class M extends HashMap<String,Object> {
  public pub
  protected pro
  @PackageScope pack
  private priv
  def prop
  def getAny() {}
  void setAny(value) {}
}
{code}
 # Read and write do not share a consistent resolution order – noted in 8555. 
Should access method selection take visibility into account? I think sender 
information is not always available to {{MetaClassImpl}} so the "inside class" 
behavior is required.
{code:groovy}
void test1(M map) {
  map.pub  // field (fixed in 5001)
  map.pro  // entry
  map.pack // entry
  map.priv // entry
  map.prop // property (fixed in 5001)
  map.any  // getter (all visibilities -- fixed in 5001) or entry for subclass 
of M (private or package-private other-package subclass -- fixed in 11357)
  map.empty // entry ("class" and "metaClass" as well)

  map.pub  = null // field
  map.pro  = null // field
  map.pack = null // entry
  map.priv = null // entry
  map.prop = null // property
  map.any  = null // setter (all visibilities) or entry for subclass of M 
(private or package-private other-package subclass -- fixed in 11357)
  map.empty = null // entry
  map.class = null // entry
  map.metaClass = null // setter via 
ScriptBytecodeAdapter#setGroovyObjectProperty
}
{code}
 # "this" and "super" have different behavior.
{code:groovy}
  // add this to the body of M
  void test2(M that) {
    this.pub  // field
    this.pro  // field
    this.pack // field
    this.priv // field
    this.prop // property
    this.prop = null // property
    this.any  // getter (all visibilities -- fixed in 5001)
    this.class // entry (dynamic) or isser (static)
    this.empty // entry or getter (static)
    this.metaClass // field (dynamic) or getter (static)

    this.pub = null // field
    this.any = null // setter (all visibilities) or entry for subclass of M 
(private or package-private other-package subclass -- fixed in 11357)
    this.empty = null // entry (dynamic) or error (static)
    this.class = null // entry (dynamic) or error (static)
    this.metaClass = null // field (dynamic) or setter (static)

    def that = this
    that.* // see test1 (except "empty", "class" and "metaClass")
    that.empty // entry (dynamic) or isser (static)
    that.class // entry (dynamic) or getter (static)
    that.metaClass // entry (dynamic) or getter (static)
  }
{code}
 # Dynamic and static compilation have different behavior.
{code:groovy}
@groovy.transform.CompileStatic
void test3(M map) {
  map.pub  // field (changed in 5001/5491)
  map.pro  // field (changed in 5001/5491: in package or subclass) or entry
  map.pack // field (changed in 5001/5491: in package)             or entry
  map.priv // entry
  map.prop // property (changed in 5001/5491)
  map.any  // getter (accessible -- changed in 5001/5491) or entry 
(inaccessible)
  map.empty // isser (changed in 5001/5491)
  map.class // getter (changed in 5001/5491)
  map.metaClass // getter (changed in 5001/5491)

  map.pub  = null // entry (changed in 6954) or field (fixed in 11376)
  map.pro  = null // entry (changed in 6954) or field (fixed in 11376)
  map.pack = null // entry
  map.priv = null // entry
  map.prop = null // property
  map.any  = null // setter (accessible) or error (inaccessible)
  map.empty = null // error "Cannot set read-only property: empty" (and 
"class") -- GROOVY-11369
  map.metaClass = null // setter via DefaultGroovyMethods#setMetaClass
}
{code}
 # Closures intercept some properties.
{code:groovy}
void test4(M map) {
  map.with {
    pub // field
    pro // entry
    pack // entry
    priv // entry
    prop // property
    directive // closure property
    metaClass // closure property (and so on for "owner", "delegate", 
"thisObject", ...)
  }
}
{code}
 # The rules change a bit for fields declared by super class.
{code:groovy}
class MM extends M {
  void test5() {
    this.pub   // field (fixed in 5001)
    this.pro   // entry
    this.pack  // entry
    this.priv  // entry
    this.prop  // property (fixed in 5001)
    this.any   // getter (public, protected, package-private if same-package) 
or entry (private, package-private if other-package)
    this.class // entry
    this.empty // entry
    this.metaClass // entry

    this.pub  = null // field
    this.pro  = null // field
    this.pack = null // entry
    this.priv = null // entry
    this.prop = null // property
    this.any  = null // setter (public, protected, package-private if 
same-package) or entry (private, package-private if other-package -- fixed in 
11357)
    this.empty = null // entry
    this.class = null // entry
    this.metaClass = null // setter via 
ScriptBytecodeAdapter#setGroovyObjectProperty
  }
}
{code}
# Calling a name bypasses map lookup.
{code:groovy}
void test6(M map) {
  map.pack() // field read and call
  map.priv() // field read and call
}
{code}

GROOVY-662, GROOVY-5001, GROOVY-5491, GROOVY-5517, GROOVY-5985, GROOVY-6144, 
GROOVY-6277, GROOVY-6954, GROOVY-8065, GROOVY-8074, GROOVY-8265, GROOVY-8555, 
GROOVY-8978, GROOVY-9127, GROOVY-11144, GROOVY-11319, GROOVY-11223, 
GROOVY-11357, GROOVY-11360, GROOVY-11368, GROOVY-11369, GROOVY-11370, 
GROOVY-11376 GROOVY-11384, GROOVY-11386, GROOVY-11387, GROOVY-11390, 
GROOVY-11401


> property semantics of map-based types
> -------------------------------------
>
>                 Key: GROOVY-11367
>                 URL: https://issues.apache.org/jira/browse/GROOVY-11367
>             Project: Groovy
>          Issue Type: Bug
>            Reporter: Eric Milles
>            Assignee: Eric Milles
>            Priority: Major
>              Labels: breaking
>
> The rules for property read and write for map-based types still have several 
> inconsistencies:
> {code:groovy}
> class M extends HashMap<String,Object> {
>   public pub
>   protected pro
>   @PackageScope pack
>   private priv
>   def prop
>   def getAny() {}
>   void setAny(value) {}
> }
> {code}
>  # Read and write do not share a consistent resolution order – noted in 8555. 
> Should access method selection take visibility into account? I think sender 
> information is not always available to {{MetaClassImpl}} so the "inside 
> class" behavior is required.
> {code:groovy}
> void test1(M map) {
>   map.pub  // field (fixed in 5001)
>   map.pro  // entry
>   map.pack // entry
>   map.priv // entry
>   map.prop // property (fixed in 5001)
>   map.any  // getter (all visibilities -- fixed in 5001) or entry for 
> subclass of M (private or package-private other-package subclass -- fixed in 
> 11357)
>   map.empty // entry ("class" and "metaClass" as well)
>   map.pub  = null // field
>   map.pro  = null // field
>   map.pack = null // entry
>   map.priv = null // entry
>   map.prop = null // property
>   map.any  = null // setter (all visibilities) or entry for subclass of M 
> (private or package-private other-package subclass -- fixed in 11357)
>   map.empty = null // entry
>   map.class = null // entry
>   map.metaClass = null // setter via 
> ScriptBytecodeAdapter#setGroovyObjectProperty
> }
> {code}
>  # "this" and "super" have different behavior.
> {code:groovy}
>   // add this to the body of M
>   void test2(M that) {
>     this.pub  // field
>     this.pro  // field
>     this.pack // field
>     this.priv // field
>     this.prop // property
>     this.any  // getter (all visibilities -- fixed in 5001)
>     this.class // entry (dynamic) or isser (static)
>     this.empty // entry or getter (static)
>     this.metaClass // field (dynamic) or getter (static)
>     this.pub = null // field (same for "pro", "pack", "priv" and "prop")
>     this.any = null // setter (all visibilities) or entry for subclass of M 
> (private or package-private other-package subclass -- fixed in 11357)
>     this.empty = null // entry (dynamic) or error (static)
>     this.class = null // entry (dynamic) or error (static)
>     this.metaClass = null // field (dynamic) or setter (static)
>     def that = this
>     that.* // see test1 (except "empty", "class" and "metaClass")
>     that.empty // entry (dynamic) or isser (static)
>     that.class // entry (dynamic) or getter (static)
>     that.metaClass // entry (dynamic) or getter (static)
>   }
> {code}
>  # Dynamic and static compilation have different behavior.
> {code:groovy}
> @groovy.transform.CompileStatic
> void test3(M map) {
>   map.pub  // field (changed in 5001/5491)
>   map.pro  // field (changed in 5001/5491: in package or subclass) or entry
>   map.pack // field (changed in 5001/5491: in package)             or entry
>   map.priv // entry
>   map.prop // property (changed in 5001/5491)
>   map.any  // getter (accessible -- changed in 5001/5491) or entry 
> (inaccessible)
>   map.empty // isser (changed in 5001/5491)
>   map.class // getter (changed in 5001/5491)
>   map.metaClass // getter (changed in 5001/5491)
>   map.pub  = null // entry (changed in 6954) or field (fixed in 11376)
>   map.pro  = null // entry (changed in 6954) or field (fixed in 11376)
>   map.pack = null // entry
>   map.priv = null // entry
>   map.prop = null // property
>   map.any  = null // setter (accessible) or error (inaccessible)
>   map.empty = null // error "Cannot set read-only property: empty" (and 
> "class") -- GROOVY-11369
>   map.metaClass = null // setter via DefaultGroovyMethods#setMetaClass
> }
> {code}
>  # Closures intercept some properties.
> {code:groovy}
> void test4(M map) {
>   map.with {
>     pub // field
>     pro // entry
>     pack // entry
>     priv // entry
>     prop // property
>     directive // closure property
>     metaClass // closure property (and so on for "owner", "delegate", 
> "thisObject", ...)
>   }
> }
> {code}
>  # The rules change a bit for fields declared by super class.
> {code:groovy}
> class MM extends M {
>   void test5() {
>     this.pub   // field (fixed in 5001)
>     this.pro   // entry
>     this.pack  // entry
>     this.priv  // entry
>     this.prop  // property (fixed in 5001)
>     this.any   // getter (public, protected, package-private if same-package) 
> or entry (private, package-private if other-package)
>     this.class // entry
>     this.empty // entry
>     this.metaClass // entry
>     this.pub  = null // field
>     this.pro  = null // field
>     this.pack = null // entry
>     this.priv = null // entry
>     this.prop = null // property
>     this.any  = null // setter (public, protected, package-private if 
> same-package) or entry (private, package-private if other-package -- fixed in 
> 11357)
>     this.empty = null // entry
>     this.class = null // entry
>     this.metaClass = null // setter via 
> ScriptBytecodeAdapter#setGroovyObjectProperty
>   }
> }
> {code}
> # Calling a name bypasses map lookup.
> {code:groovy}
> void test6(M map) {
>   map.pack() // field read and call
>   map.priv() // field read and call
> }
> {code}
> GROOVY-662, GROOVY-5001, GROOVY-5491, GROOVY-5517, GROOVY-5985, GROOVY-6144, 
> GROOVY-6277, GROOVY-6954, GROOVY-8065, GROOVY-8074, GROOVY-8265, GROOVY-8555, 
> GROOVY-8978, GROOVY-9127, GROOVY-11144, GROOVY-11319, GROOVY-11223, 
> GROOVY-11357, GROOVY-11360, GROOVY-11368, GROOVY-11369, GROOVY-11370, 
> GROOVY-11376 GROOVY-11384, GROOVY-11386, GROOVY-11387, GROOVY-11390, 
> GROOVY-11401



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

Reply via email to