Friday, 12 January 2007

More detail on Property Literals / Property Objects

A little more clarity on my property literal proposal (as it seems to have become named).

The aim is to provide compiler checked access to properties, simplifying the relationship between applications and frameworks. Currently, we write (where person is the bean being worked on):

  binder.bind( person, "surname" );

Property literal syntax replaces this:

  binder.bind( person->surname );

Thus, the arrow operator on a bean returns an object which refers to a specific property on an actual bean instance.

Property literal syntax also allows you to bind to the meta-property, which is the property without a reference to any particular bean instance (where Person is the class name):

  binder.bindMeta( Person->surname );

Finally, there is the possibility of using the same syntax for references to methods:

  binder.bind( person->validate() );
  binder.bindMeta( Person->validate() );

The property can be used by the framework to access the bean in one of these ways (depending on whether you have a property or meta-property - ie. one that is bound or unbound to a specific bean):

  String value = property.get();
  String value = metaProperty.get(beanInstance);

The real question is how to connect these properties to the bean itself. There are two basic ways:

The first is the classical approach, where the PropertyImpl uses reflection to access the get/set methods. In fact, PropertyImpl doesn't even appear in the bean code at all, as it is just generated by the -> operator. So this bean is nothing special at all, all the magic is in the reflection in PropertyImpl.

  public class Person {  // ie. this is a 'normal' bean
    private String surname;
    public String getSurname() { return surname; }
    public void setSurname(String surname) {  this.surname = surname;  }
  }

So this bean is nothing special at all, all the magic is in the reflection in PropertyImpl.

The second approach is much more powerful and OO, but uses more memory.

  public class Person {
    private Property<Person, String> surname =
        new PropertyImpl<Property, String>(this, "surname");

    public String getSurname() {
      return surname.get();
    }
    public void setSurname(String surname) {
      surname.set(surname);
    }
  }

With this structure, the class PropertyImpl can be varied according to what kind of property it is. Thus, if you need a bound property then you simply use BoundPropertyImpl instead.

The classical approach uses less memory, is more proven, and is probably better for the server-side where memory and scalability matter. The second approach requires one object for each property, and probably works better for swing GUIs, which require lots of events to fly about.

For reference, the system at my day-job uses property objects. As we don't have property literals and the arrow operator, we just code-generate lots of methods instead. It has a similar effect, except that only frameworks written by us know about the property objects. As a result, we currently have proprietry frameworks. It would be great if Java could unite around property literals (and method literals?) for interacting between objects, and thus gain the benefts we see in this coding style.

5 comments:

  1. The property object does not need a reference to this, which means it can be static. For example, this:
    class Foo {
    @Property String bar;
    }
    ...could be 'compiled' into:
    class Foo {
    public static Property $Property_bar = new java.lang.Property {
    public void set(Foo base, String value) { base.bar = value; }
    public String get(Foo base) { return base.bar; }
    }
    String bar;
    }

    Which would work just fine for bindings.

    It would also be fabulous if at developers could provide different implementations for $Property_Bar:
    @Property{NotNullProperty.class} String bar;
    @Property{ObservableProperty.class} String baz;
    ... or my personal favourite, where you can chain properties to do things like this:
    String @Property{ObservableProperty.class, NotNullProperty.class} baz;

    I describe a potential API for 'extensible properties' here:
    http://publicobject.com/2007/01/extensible-properties-for-java-language.html

    ReplyDelete
  2. ... and the value of the property objects being static is that they don't consume additional memory* per instance.

    ReplyDelete
  3. Stephen Colebourne12 January 2007 10:09

    @Jesse, This is a third option for compilation, however its actually very close to the first option I described - use reflection. BTW, in the naming scheming I'm using, you are creating a meta-property, not a property. Thus your classes are ObservableMetaProperty and so on. In my naming, the real property holds both the meta-property and the bean it is active for. See javadoc at http://joda-beans.sf.net

    ReplyDelete
  4. You're right, Meta-property vs. Property is a good distinction.

    In most cases I think I prefer MetaProperty. But for areas like ORM, Properties could have additional fields to store instance-specific metadata on a field such as 'isDirty' or 'originalValue'.

    ReplyDelete
  5. I don't have a whole lot to add to the worldwide property discussion; I am interested in the concept of Property, and more importantly, MetaProperty objects as an obvious complement to the existing reflection packages. However I can't see any reason to force developers to manually code Property objects when syntax sugar would do. Leave the internal implementations as close to "current" as possible and let the (augmented) compiler generate as much as possible. Not breaking new ground, but ATM my ideal syntax is:

    private String property(:(read|write)only)? foo;

    This keeps the existing means of scoping access to "foo". It is fairly pleasant semantically. I have seen some examples like:

    public property private String foo;

    But I think we can make a blanket statement that a property's getters and setters, if applicable, are public, especially during any POC phase. Otherwise Property wouldn't have access to delegate to the appropriate methods without VM support or tricky reflection (changing accessibility of methods at runtime). The net effect of this decision is that a single access modifier, that of the actual member variable, is the only one necessary. I suppose there is no reason the type and property need appear in that order in case it is visually more pleasing to some the other way:

    private property(:(read|write)only)? String foo;

    Finally, while it might be something to be discouraged, it might be acceptable to make static properties available as well. Probably the Property object for a static property would simply ignore the bean parameter on its setter and getter. This would be consistent with the reflection API IMO.

    To keep the class defs clean, one might define things such that there was not direct API access to the Property instance. i.e. bean->someProperty would evaluate to bean.getClass().getMetaProperty("someProperty").get(bean) or the like.

    As for Jesse's "extensible properties" idea, I can see what you're after here, but this seems to amount to Property decorators. So perhaps any language support of properties might just be designed in such a way that setting up decorators via injection or AOP would be trivial. Obviously this would require more thought.

    $0.02,
    Matt

    ReplyDelete