The Source for Java Technology Collaboration
User: Password:



Cay Horstmann

Cay Horstmann's Blog

Pie in the Sky Properties

Posted by cayhorstmann on January 10, 2007 at 12:07 PM | Comments (6)

The Rules of the Game

???

  • This is just a Gedankenexperiment. I am not seriously proposing anything for Java SE7.
  • A property is an abstract thing that has a get and set operation.
  • A "native property" is a "property done right" with new syntax. A "JavaBeans property" is what it always was.
  • I don't want to get into any syntax wars. I use an uppercase Pi (Π) to denote a property keyword (such as public Π int salary) and a lowercase pi (π) to denote property access (such as joe π salary). This "pi in the sky" syntax is absolutely certain not to get adopted. Substitute your own favorites, such as dot, arrow, or whatever.
  • For compatibility, java.beans.Introspector includes native properties in BeanInfo.getPropertyDescriptors.
  • Anyone who wrote tools that enumerated get/set methods with a mechanism other than java.beans.Introspector should go and pound sand.
  • No bleating about "you are destroying encapsulation" and "why don't you just make your fields public". The point of a property is to encapsulate read/write operations that are deemed essential features of a class and whose implementation can evolve over time.

Mangled Methods

The way I understand Jacob's argument is that the get/set naming convention deserves to be laid to rest as a historical {accident|mistake|good idea at the time}. Thus, a native property must be manipulated with the property operator. If you define

public class Employee
{ public Π double salary; . . . }

then you must use

double x = joe π salary;

or

joe π salary += 1000;

You cannot use

double x = joe.getSalary();

or

joe.setSalary(joe.getSalary() + 1000);

Conversely, when translating the expression

x = joe π foo; // never calls getFoo

the compiler would not start hunting for a getFoo method. If there was no property foo , the expression would simply be an error.

By default, properties would presumably be implemented as a private field and a pair of public methods, with mangled names, similar to mangling in inner classes. For example,

public class Employee
{ private double $salary; public void $salary$set(double); public double $salary$get(); . . .
}

The getReadMethod and getWriteMethod of java.beans.PropertyDescriptor return the Method objects of these methods, so they can be invoked reflectively in tools.

The JavaBeans specification makes it quite clear that properties are intended for tools. The GUI builder or the persistence provider has a legitimate need to access properties that may be different from the needs of the programmer. Maybe one shouldn't even have a property access operator? Or should tool properties simply be private?

When you have a private property, the methods would still be generated, but they are only accessible through introspection (when access control permits), or as this π property in other methods of the same class.

Property Annotation Issues

Of course, annotations should be updated to work with native properties. Something like

@OneToMany
private Π Collection<Choice> choices;

Ideally, a property annotation is associated with the property itself and not with a method or field. But annotations are placed into the class files. Do we want to have yet another class file format change that can express properties and property annotations???

What about compatibility with existing tools and standards? The JPA annotation processor currently handles annotations of either fields or getters. Should annotating a property automatically produce a field annotation? Should there be syntax for moving the annotation to the getter method instead? Or the other way around???

Stuff that Needs Syntax

The most common use case--a field with a trivial getter and setter--should require no boilerplate. There need to be various variations for get-only properties, properties with nontrivial getters and setters, etc. etc. I don't want to propose syntax for them, so I just tabulate what needs to be supported with some syntax

Get-only property object π property cannot be an lvalue
Set-only property object π property cannot be an rvalue
Public getter/private getter? Does one want such a fine-grained control, or should the programmer just supply a private property and a public getter method?
Explicit getter/setter that does something else The programmer supplies a getter/setter that does something else than just reading or writing the underlying field. For example, a getter for a name property might concatenate firstName and lastName. Of course, the method is still anonymous. For example, something like
public Π String name get { return firstName + " " + lastName; }
would produce a method with a mangled name such as $name$get.
Explicit getter/setter that accesses hidden field The programmer supplies a getter/setter that accesses the hidden field and also does something else, e.g. logging. What is the syntax for accessing the hidden field?
No field Not all properties give rise to a field, e.g. the name property described above. Perhaps the compiler should simply see whether the getter and setter don't access the hidden field?
Bound properties Bound properties fire listeners when the setters are called. Apparently, they are very important to some people in the Swing world. This blog article discusses some subtleties. I am really muddled about these. Would users want a separate listener for each property, or a single listener for all properties of an object? Would it be ok to synthesize the listener firing method by calling the getter before and after invoking the setter, or would users want to customize that?
Constrained properties? Constrained properties allow a veto before property changes. These are really obscure. I have never used them (except for JInternalFrame, and then only because the API forced me to). Does anyone care?
Indexed properties? The JavaBeans spec defines array-valued indexed properties with getter and setter methods for individual elements, but I have never seen them used in practice.
Property literals? A comment to this article suggests that one might want to pass around a typed property literal (such as joe π salary) for some purpose, e.g. querying its capabilities, deferred execution of the getter/setter, etc.

All of this seems pretty easy to do. The challenge is to come up with syntax that makes people happy.


Bookmark blog post: del.icio.us del.icio.us Digg Digg DZone DZone Furl Furl Reddit Reddit
Comments
Comments are listed in date ascending order (oldest first) | Post Comment

  • Bound properties: The advantage of PropertyChangeListener over, say, ChangeListener is that you only have to allocate one object per observable-observer pair. The downside is that the code sucks big time. If you want maintainable code, ignore Beans on this particular issue.

    Constrained properties: Vetoable properties are rare and highly unpleasant to use. Properties that don't permit, for instance, null (should be your default) or will only take data that will fit into the database, are common and vital.

    Indexed properties: Used with in Swing itself. Very rarely are they actually used correctly. They don't make any sense. What you actually want is a property of type List or a read-only reference to a 'smart object' like ListModel (although that interface isn't brilliant).

    "Property literals": That's exactly what I want. I want to take the live property of a tick box and use it as the enabled/disabled property of some other components. Or to take a text property of an object and create a text field for it, with no further messing. I don't want to piss about trying to duplicate state from one place to another, like the pure evil of JSR295. State (as opposed to input) listeners should be about updating displays, not mutating data.

    Posted by: tackline on January 10, 2007 at 02:25 PM

  • It strikes me that one of the problems properties are trying to solve is Java's violation of the Uniform Access Principle. Perhaps it would make more sense to address the root cause of that problem, rather than trying to work around it?

    And yes, property literals would kick ass - I have a need for them in my current project and I'm still trying to decide which workaround (== hack) I dislike least.

    Posted by: pmonks on January 10, 2007 at 03:07 PM

  • If you want to help write a more formal property literal doc, please contact me at stephen**joda.org. Unfortunately, its been a long time since I used Swing, so I'm struggling coming back to the listener complexities.

    Posted by: scolebourne on January 10, 2007 at 03:35 PM

  • I'll reiterate what I wanted on the Java champion's list-- C# syntax :-) I thought about doing another blog, but I see another blog basically was going to say the same thing. Think about the refactoring of:
    public class Employee {
    @Column("empId")
    public String id;
    }

    Employee emp = mngr.find("1");
    String id = emp.id;


    To:

    public class Employee {
    @Column("empId")
    private String _id;

    public String id {
    get { return this._id; }
    set(String in) { this._id = id; }
    }
    }

    Employee emp = mngr.find("1");
    String id = emp.id;

    All code that uses Employee, doesn't change, but you've been able to encapsulate member variables with C# syntax. Another (possibly dumb) idea which would extend fields a bit more implicitly without requring a separate property declaration:

    public class Employee {
    @Column("empId")
    public String id {
    get { return super.get(); }
    set(String in) { super.set(in); }
    }
    }

    Maybe that's the implicit behavior for fields, and the fact that you delegate to a member field is basically an override. As for the listeners, Bean API, etc-- maybe we just leave that all alone and allow a shift pure member variables as properties?

    Posted by: jhook on January 10, 2007 at 04:57 PM

  • Hmm. Concerning the Uniform Access Principle on Wikipedia, I think Ruby is a better example than Python, and Ruby is also closer to original Eiffel, I'm pretty sure. But I don't have the time to research before undertaking to update the Wikipedia entry accurately.

    Posted by: tompalmer on January 11, 2007 at 03:36 PM


  • I think that this is better variant:

    @FieldAccess(accessType=FieldAccessType.ReadWrite,
    access=AccessType.Public,
    propertyChangeSupport=true,
    propertyChangeNotifyStrategy=PropertyChangeNotifyStrategy.Always)
    class A
    {

    private int int1;

    @FieldAccess(accessType=FieldAccessType.Read,
    access=AccessType.Protected,
    propertyChangeSupport=false,
    propertyChangeNotifyStrategy=PropertyChangeNotifyStrategy.ReallyChanged)
    private int int2;

    public static void main(String[] args)
    {
    A a = new A();
    a.setInt1(1);
    a.getInt1();

    a.getInt2();
    // Set Int2 is not available
    // a.setInt2(2);

    }
    }

    Posted by: miro on January 09, 2008 at 01:20 PM



Only logged in users may post comments. Login Here.


Powered by
Movable Type 3.01D
 Feed java.net RSS Feeds