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

property semantics of map-based types (pt.2)

Details

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

    Description

      The property semantics for map-based types was recently updated (see GROOVY-11367). testRead3() and testRead4() demonstrate the desired outcome: public members (except isEmpty() and getClass()) then map get/put.

      testRead1() and testRead2() demonstrate the differing semantics for this references: accessible fields and public methods then map get/put. Why the difference between fields and methods? Also there are differences between dynamic and static compilation modes (as noted).

      import groovy.transform.*
      class M implements Map<String,String> {
        @Delegate Map<String,String> map = [:].withDefault{ 'entry' }
      
        public        a = 'field'
        protected     b = 'field'
        @PackageScope c = 'field'
        private       d = 'field'
        Closure       e = { 'called' }
      
        public        getF() { 'getter' }
        protected     getG() { 'getter' }
        @PackageScope getH() { 'getter' }
        private       getI() { 'getter' }
      
        public        void setF(f) { 'setter' }
        protected     void setG(g) { 'setter' }
        @PackageScope void setH(h) { 'setter' }
        private       void setI(i) { 'setter' }
      
        void testRead1() {
          println a         // field
          println b         // field
          println c         // field
          println d         // field
          println e         // proper
          println f         // getter
          println g         // entry (dynamic) or getter (static)
          println h         // entry (dynamic) or getter (static)
          println i         // entry (dynamic) or getter (static)
          println j         // entry
          println empty     // entry (dynamic) or isser  (static)
          println metaClass // field (dynamic) or getter (static)
          println "";
          {->
          println a         // field
          println b         // entry
          println c         // entry
          println d         // entry
          println e         // proper
          println f         // getter
          println g         // entry
          println h         // entry
          println i         // entry
          println j         // entry
          println empty     // entry
          println metaClass // getter (of Closure)
          }()
        }
      
        void testRead2() {
          println this.a         // field
          println this.b         // field
          println this.c         // field
          println this.d         // field
          println this.e         // proper
          println this.f         // getter
          println this.g         // entry (dynamic) or getter (static)
          println this.h         // entry (dynamic) or getter (static)
          println this.i         // entry (dynamic) or getter (static)
          println this.j         // entry
          println this.empty     // entry (dynamic) or isser  (static)
          println this.class     // entry (dynamic) or getter (static)
          println this.metaClass // field (dynamic) or getter (static)
          println "";
          {->
          println this.a         // field
          println this.b         // entry (dynamic) or field (static)
          println this.c         // entry (dynamic) or field (static)
          println this.d         // entry (dynamic) or field (static)
          println this.e         // proper
          println this.f         // getter
          println this.g         // entry (dynamic) or getter (static)
          println this.h         // entry (dynamic) or getter (static)
          println this.i         // entry (dynamic) or getter (static)
          println this.j         // entry
          println this.empty     // entry (dynamic) or isser  (static)
          println this.class     // entry (dynamic) or getter (static)
          println this.metaClass // getter
          }()
        }
      
        void testRead3() {
         def that = this
          println that.a         // field
          println that.b         // entry
          println that.c         // entry
          println that.d         // entry
          println that.e         // proper
          println that.f         // getter
          println that.g         // entry
          println that.h         // entry
          println that.i         // entry
          println that.j         // entry
          println that.empty     // entry
          println that.class     // entry
          println that.metaClass // getter
          println "";
          {->
          println that.a         // field
          println that.b         // entry
          println that.c         // entry
          println that.d         // entry
          println that.e         // proper
          println that.f         // getter
          println that.g         // entry
          println that.h         // entry
          println that.i         // entry
          println that.j         // entry
          println that.empty     // entry
          println that.class     // entry
          println that.metaClass // getter
          }()
        }
      
        void testRead4() {
          this.with {
            println a         // field
            println b         // entry
            println c         // entry
            println d         // entry
            println e         // proper
            println f         // getter
            println g         // entry
            println h         // entry
            println i         // entry
            println j         // entry
            println empty     // entry
            println metaClass // getter (of Closure)
          }
          def that = this; println ""
          that.with {
            println a         // field
            println b         // entry
            println c         // entry
            println d         // entry
            println e         // proper
            println f         // getter
            println g         // entry
            println h         // entry
            println i         // entry
            println j         // entry
            println empty     // entry
            println metaClass // getter (of Closure)
          }
        }
      }
      

      Attachments

        Issue Links

          Activity

            emilles Eric Milles added a comment - - edited

            "entry (dynamic) or getter (static)" differences have been normalized. Non-public access methods will not be considered as properties regardless of "this" semantic.

            https://github.com/apache/groovy/commit/080277e23d7374bd93d62d3a4706aab66d36a01d
            https://github.com/apache/groovy/commit/e94a1960626147df8a107ad03bf92be7e39da0d9

            This leaves only the explicit-this (within closure) field section of testRead2() with a difference, which may be same or similar to GROOVY-11402.

            emilles Eric Milles added a comment - - edited "entry (dynamic) or getter (static)" differences have been normalized. Non-public access methods will not be considered as properties regardless of "this" semantic. https://github.com/apache/groovy/commit/080277e23d7374bd93d62d3a4706aab66d36a01d https://github.com/apache/groovy/commit/e94a1960626147df8a107ad03bf92be7e39da0d9 This leaves only the explicit- this (within closure) field section of testRead2() with a difference, which may be same or similar to GROOVY-11402 .
            emilles Eric Milles added a comment - - edited

            One additional difference exists between dynamic and static modes when it comes to super class field access:

            abstract class A {
              public        x = 'field'
              protected     y = 'field'
              @PackageScope z = 'field'
            }
            class M extends A implements Map<String,String> {
              // ...
              void testRead5() {
                println x      // field
                println y      // entry (dynamic) or field (static)
                println z      // entry (dynamic) or field (static)
                println this.x // field
                println this.y // entry (dynamic) or field (static)
                println this.z // entry (dynamic) or field (static)
              }
              void testWrite() {
                a = null      // field
                b = null      // field
                x = null      // field
                y = null      // entry (dynamic) or field (static)
                z = null      // entry (dynamic) or field (static)
                println(this); clear()
                this.a = null // field
                this.b = null // field
                this.x = null // field
                this.y = null // entry (dynamic) or field (static)
                this.z = null // entry (dynamic) or field (static)
                println this
              }
            }
            

            GROOVY-8978 is a variant of this.

            emilles Eric Milles added a comment - - edited One additional difference exists between dynamic and static modes when it comes to super class field access: abstract class A { public x = 'field' protected y = 'field' @PackageScope z = 'field' } class M extends A implements Map< String , String > { // ... void testRead5() { println x // field println y // entry (dynamic) or field (static) println z // entry (dynamic) or field (static) println this .x // field println this .y // entry (dynamic) or field (static) println this .z // entry (dynamic) or field (static) } void testWrite() { a = null // field b = null // field x = null // field y = null // entry (dynamic) or field (static) z = null // entry (dynamic) or field (static) println( this ); clear() this .a = null // field this .b = null // field this .x = null // field this .y = null // entry (dynamic) or field (static) this .z = null // entry (dynamic) or field (static) println this } } GROOVY-8978 is a variant of this.
            emilles Eric Milles added a comment - https://github.com/apache/groovy/commit/93f0d096c5c23256add266ff8f0f7d6a953a65ee

            People

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

              Dates

                Created:
                Updated:
                Resolved: