Uploaded image for project: 'Groovy'
  1. Groovy
  2. GROOVY-11367

property semantics of map-based types

    XMLWordPrintableJSON

Details

    • Improvement
    • Status: Closed
    • Major
    • Resolution: Fixed
    • None
    • 5.0.0-alpha-9
    • None

    Description

      The rules for property read and write for map-based types still have several inconsistencies:

      class M extends HashMap<String,Object> {
        public pub
        protected pro
        @PackageScope pack
        private priv
        def prop
        def getAny() {}
        void setAny(value) {}
      }
      
      1. 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.
        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
        }
        
      2. "this" and "super" have different behavior.
          // 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)
          }
        
      3. Dynamic and static compilation have different behavior.
        @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
        }
        
      4. Closures intercept some properties.
        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", ...)
          }
        }
        
      5. The rules change a bit for fields declared by super class.
        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
          }
        }
        
      6. Calling a name bypasses map lookup.
        void test6(M map) {
          map.pack() // field read and call
          map.priv() // field read and call
        }
        

      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-11393, GROOVY-11401, GROOVY-11402

      Attachments

        Issue Links

          Activity

            People

              emilles Eric Milles
              emilles Eric Milles
              Votes:
              0 Vote for this issue
              Watchers:
              1 Start watching this issue

              Dates

                Created:
                Updated:
                Resolved: