A Late Entry

Greg Zoller gzoller at hotmail.com
Sun Aug 9 09:24:04 PDT 2009


Members of coin-dev...  I'm writing to submit a late proposal for the Java language, if not for initial Java 7 release (probably too late) but perhaps for a later release.  Below is the proposal form.  Plain text editor formatting is pretty inconsistent, so apologies if it looks poorly formatted when you see it.


Project Coin

Late Submission: Hiding Accessors at Compile Time

AUTHOR:  Greg Zoller
         gzoller(atsign)hotmail.com

OVERVIEW:

    Feature Summary:
        De-clutter classes littered with accessors by having the 
        compiler auto-generate trivial accessors for data members
        denoted with a @property annotation.
    
    Major Advantage:
        Would eliminate lots (and lots) of messy get/set code 
        without losing the benefits of having an accessor for the
        times you really need them.  The proposed approach should 
        not break any existing code not written to take advantage 
        of the new capability.
        
    Major Benefit:
        Less cluttered code!  Removes (or more specifically hides 
        behind the compiler) the clumsy construct of accessors 
        without losing the purpose and benfits of their existence.
        In other words, I want property accessor capability--I
        just don't want to see them!
        
    Major Disadvantage:
        None that come to mind--I'm sure someone will contribute a
        disadvantage.
        
    Alternatives:
        Leave things the way they are.
        
EXAMPLES:

    /* Today */
    public class Foo {
        private String name;  // no accessors for name
        private int age;
        private double balance;
        private String comment;
        
        public int getAge() { return this.age; }
        public void setAge(int age) { this.age = age; }
        public double getBalance() { return this.balance; }
        public void setComment(String comment) { 
            this.comment = comment; }
    }
    
    /* Proposed */
    public class Foo {
        private String name;  // no accessors generated
        @property private int age;  // both get/set generated
        @property(GET) private double balance;  // getter generated, no setter
        @property(SET) private String comment;  // setter generated, no getter
    }
    
    // Code would use these properties via their generated 
    // accessors as they do now:    
    foo.setAge(foo.getAge() + 10);

    // EVEN BETTER... the compiler can try to resolve data member
    // access according to a scope/visibility hierarchy: 
    //       public member, protected member, private member,
    //       inserted getter/setter call
    
    // If this can be done in the compiler then old code can still 
    // call the accessors like always while new code could simply 
    // have:
    
    foo.age += 10;
    System.out.println("Age: "+foo.age);
    
    // This looks as clean as direct data member access but age
    // remains private with all the benefits of having accessor 
    // protection.  In the example above assuming no public, 
    // protected, or private visibility for age exists the compiler 
    // will insert a call to foo.getAge() for the programmer if age
    // is a @property field (otherwise its a compile error).
    
    // NOTE:  The compiler won't auto-generate a getter or setter if 
    // one already has been specified by the programmer, allowing 
    // full control like we have now:
    
    public class Foo {
        @property private int age;  // only a trivial getter generated--setter exists
        public void setAge(int age) {
            msg.notify("Someone's tampering with age!");
            this.age = age;
        }
    }

    // The compiler would exercise precedence logic in deciding 
    // whether to insert a call to the accessors or not
    
    package A;
    public class Foo {
        @property private int age;  // only setter generated--getter exists
        public int getAge() {
            System.out.println("Getter called!");
            return this.age;
        }
        public void something() {
            int anotherAge = this.age;  
            // private visibility is valid--no compiler-inserted
            // call to this.getAge() here
            
            int oneMoreAge = this.getAge();
            // explicit call to getter ok--just like today
        }
    }
    
    package B;
    public class Bar {
        public void blah(Foo foo) {
            System.out.println(foo.age);  
            // Compiler can't resolve public, protected, or 
            // private visibility to foo.age so a call to the
            // generated foo.getAge() accessor is inserted
        }
    }
    
DETAILS

    Specification:
        Add the FIELD-targeted @property annotation to the
        language.  Without parameters this will cause the 
        generation of both a getter and setter unless one is 
        already given by the programmer.

        Optional parameters GET or SET (@property(GET) or 
        @property(SET)) would only attempt to generate the getter
        or setter respectively.  I don't think Java grammar would
        be affected (?).
        
    Compilation:
        Out of my depth here.  The auto-generation feature *should*
        be very straightforward as I would hope all the needed info 
        to create the getters/setters is available at compile-time.
        I'm less clear on whether the compiler would be able to do
        the auto-resolution so you could just use foo.age and 
        wouldn't be forced to call foo.getAge()/foo.setAge(), but
        I'm hopeful this is also possible, as it would be a great
        feature.
        
        This logic would have to support a hierarchy of resolution
        so that if 'age' was a public    data member then public 
        access would take precedence over trying to call the 
        accessor method.  Likewise protected and private access 
        would take precedence over the getter if normal
        visibility rules allowed this mode of access.
    
    Testing:
        Hmm...
    
    Library Support:
        Shouldn't require any library support
        
    Reflective APIs:
        Existing APIs should be fine.  The generated
        getters/setters would be reflectively accessible since once 
        they are generated by the compiler they are no different 
        than if the programmer had written them.
        
    Other Changes:
        None come to mine.
        
    Migration:
        No conversion necessary.  Normal getter/setter code in
        common use today would still work and could live seamlessly 
        in parallel with code using the new features.
        
COMPATIBILITY:

    Breaking Changes:
        No code should break due to the changes proposed
        
    Existing Programs:
        Existing code should live seamlessly in parallel to these
        changes.  If the compiler access precidence feature is 
        implemented then newly written code can take advantage of 
        this ability when calling existing unmodified code.  For 
        example:
        
        // Existing code
        public class Foo {
            private int age;
            public int getAge() { return this.age; }
            public void setAge(int age) { this.age = age; }
        }
        
        // New code
        foo.age = 10; 
        
        // compiler would first see if a public/protected/private
        // visible age data member existed, and since there is none 
        // a call to getAge() would be inserted during compile time 
        // thus using the new feature to seamlessly interact with 
        // legacy code without altering semantics
        
REFERENCES:
    N/A


_________________________________________________________________
Get free photo software from Windows Live
http://www.windowslive.com/online/photos?ocid=PID23393::T:WLMTAGL:ON:WL:en-US:SI_PH_software:082009


More information about the coin-dev mailing list