Monday, 15 January 2007

A 'bean' keyword?

In the talk about properties, I don't think I've seen anyone mention using a 'bean' keyword. Here's a thought experiment to see how it might work.

Bean keyword

  public bean Person {
    // properties
    property String forename;
    property String surname;

    // normal fields and methods
    private String ordinaryField;
    public boolean validate() { ... }
  }

This would be compiled to:

  public class Person implements Bean {
    // properties
    private String forename;
    private String surname;
    public String getForename() { ... }
    public void setForename(String forename) { ... }
    public String getSurname() { ... }
    public void setSurname(String surname) { ... }

    // normal fields and methods
    private String ordinaryField;
    public boolean validate() { ... }

    // from Bean interface
    public MetaBean metaBean() { ... }
    public Property property(String propertyName) { ... }
    public Map<String, Property> propertyMap() { ... }
  }

So what have we got? Firstly, neither the 'bean' or 'property' keyword would break existing code. Keyword 'bean' would a contextual keyword, used in place of 'class'. Keyword 'property' is also contextual, in that it can only appear inside a bean.

The 'bean' keyword acts like the 'enum' keyword. It causes the generated class to implement a JDK interface - Bean. Code is generated to implement the interface allowing dynamic access to the property objects of the bean. The keyword also triggers the code generation of the get/set methods.

The trouble is that the 'bean' keyword hasn't really changed the nature of the problem. There are still two basic types of bean (simple semi-encapsulated classes, often server-side data transfer objects, and rich event-firing classes, usually client-side). The keyword hasn't helped us define the scope of the property, readonly/writeonly, bound/constrained, validation, etc.

Abandoning the past

What if we leave existing bean conventions in the past? Well, then we might have something that makes more sense. What if the 'bean' keyword generated this code instead:

  public class Person implements Bean {
    // public final properties
    public final Property<Person,String> forename = ...
    public final Property<Person,String> surname = ...

    // normal fields and methods
    private String ordinaryField;
    public boolean validate() { ... }

    // from Bean interface
    public MetaBean<Person> metaBean() { ... }
    public Property<Person,?> property(String propertyName) { ... }
    public Map<String, Property<Person,?>> propertyMap() { ... }
  }

Now, each property is actually no more than a public final field on the bean. But, using this code-generation is very different from at present:

  String surname = person.surname.get();
  person.surname.set( person.surname.get().toUpperCase() );
  person.surname.addListener(someListener);   // client-side only?

So, application code has to use person.surname.get() instead of person.getSurname(), to access data. This is true property objects - and a much better design than a get/set method naming convention.

Is this viable? Yes, although performance would need careful analysis. The beans Introspector could probably cope with the new structure, so most existing frameworks would still work.

But is it realistic? Well, I can hear the howls of protest now, so probably not. The change could be sweetened by generating regular get/set methods on the Person class itself that delegate to the property object. But if this is truly a new beans feature in the language then why look to the past?.

Summary

On its own, a 'bean' keyword doesn't look that useful. The main problem is still in defining the properties. The main use I could think of was using it to identify a completely new type of JavaBean, following a specification completely different to JavaBean spec 1.0. And that seems unrealistic.

6 comments:

  1. Sometimes the firing of PropertyChangedEvents is done on when a set of "beans" changes, not when one does... I have been in the situation that i've made various setters with PropertyChangeSupport, (on a class that changed the styles of documents) and those then had to be made private, and exposed with a "huge" setter that set all at once since firing this modification event only made sense once.

    ReplyDelete
  2. I'm not sure why you would need 'property' if you had 'bean'. Just make all public fields properties anyway.

    public bean Movie
    {
        public Date startTime;
    public String name;

    //then, optionally:
    public String setName(String name)
    {
    if (name!=null && etc.)
    this.name=name;
    }
    }

    Outside of a constructor or the relevant setter/getter, this.name= would call the set method rather than access the field directly.

    ReplyDelete
  3. Stephen Colebourne15 January 2007 16:53

    @194, It sounds like your use case required a new bean to hold the fields that change en masse, so the set is a set of the holder bean.

    @Ricky, Yes, with a 'bean' keyword, you might get away without a 'property' keyword. However, I was trying to allow for ordinary non-property fields as well.

    BTW, a side effect of have a 'bean' keyword is that the a property access syntax could be restricted to only work on classes implementing 'bean'. Thus, there would be no clash with existing code, or dual meaning for the dot operator.

    ReplyDelete
  4. Wonderful! You're onto something! I just don't see why a bean would need regular fields.

    I had to think about those issues too, but I was writing a persistence engine (Tiny Marbles), so I could enforce my new rules and disregard the old stuff.

    ReplyDelete
  5. Tiago: there is no predicting what non-property data any object might need internally. One ready example: one might cache a hashcode value in a private variable, thereby avoiding the cost of calculating the hashcode every time it is requested when the object--and therefore its hashcode--hasn't changed.

    Stephen: I can see the potential here. And with the Enum example you've shown the precedent for a language feature triggering an interface implementation. :)

    ReplyDelete
  6. I'mc the ip 194 above. Yes, i explayned this badly. That was what i was already doing: There was a class (the bean) that had the properties that were changing. Since the event should have only be fired once, i had to modify my propertyChange fire calls from a< set of setters in the class to only one method that fired a state changed event (if any of the now private setters was called with a different value). This is why i'm not convinced by the property support proposed until now. It doesn't take in account this usecase that is IMO much more irritating than the simple usecase of a settter of a property with a fireStateChanged(FLAG_OF_PROPERTY, old, new) at the end.

    ReplyDelete