The Source for Java Technology Collaboration
User: Password:



Rémi Forax's Blog

January 2007 Archives


Property Reloaded

Posted by forax on January 23, 2007 at 08:26 AM | Permalink | Comments (27)

This entry is the second draft of my property proposal, i have tried to gather all the ideas proposed since my first post about properties.

Why do we need a property syntax in Java ?

If you have not followed the different blogs, i recommend you to first read properties in Java by Richard Blair and Properties are design features by Cay Horstmann.

Declare a property

There is three kind of property, simple property that are translated to a field plus a getter and a setter automatically generated by the compiler, user-defined property, a property for which getter and setter are defined by the developer and abstract property, a property for which getter and setter are abstract. All kind of properties can be read-only, write-only or read-write.

  class MyBean {
    public property String name1; // read-write
    public property String name2 get; // read-only
    public property String name3 set; // write-only
    public property String name4 get set; // illegal

    public property String name5 get { return "hello"; } // read-only
    public property String name6 set(String name) { } // write-only
    private String _name7;
    public property String name7
      get { return _name7; }
      set(String name) { _name7 = name; firePropertyChange(name7); } // read-write
  }

As i have already said, property, get and set are not real keywords but only local keywords. A property is implicitly read-write so the syntax for name4 is illegal. All other combinations that the ones above are invalid. You can also notice that if the property is not abstract and ends with a semi-colon, a field is created.

Access to a property

Unlike my first proposal, i think now that we must not have two ways to access to a property. So 'dot' can't be used to access/change the value of a property (It has another meaning, see further). In order to permit retrofitting of already existing code, properties are accessed using getXXX/setXXX. It's a little awkward especially for beginners but i really think that is the best solution.

 MyBean bean = new MyBean();
 bean.setName1(bean.getName2());

Property Litteral

Because i'm lazy, instead of defending myself property literal, i prefer to redirect you to Evan Summers's property reference or Stephen Colebourne's property objects
Matthias Ernst proposed to create a property object by property and by object. I think it is not very feasible due to the memory comsumption. I think a system ala java.lang.reflection, i.e. one property object by property and not related to an instance is more realisic.

I propose to use dot on the class to access to such object.

  Bean bean = new Bean("joe", "forax"); 
  Property<Bean, String> name = Bean.name;
  name.set(bean, "rémi");
  Property<Bean, String> lastname = Bean.lastname;
  String myname= lastname.get(bean);

A property literal is like .class, it acts like a static final field. The compiler translates ClassName.propertyName to ClassName.class.getProperty("propertyName").
Perhaps the property object can be cached to avoid one lookup by call like .class in transalted by the compiler in pre-tiger release.

Property Litteral and generics

The idea is to make Property safe, so a property is typed using generics. I propose to parametrize a property objet Property by its bean type and the type of its value.

 Property<Bean, String> prop = Bean.name;

Bound Property

A simple property can be bound to make swing hackers happy. If such property is defined in the class, a method propertyChange() is required in the class or in on of its supertypes. A bound property is always read-write.

 class Point {
    public property int x bound;
    public property int y bound;

    private <T> void propertyChange(Property<Point, T> prop, T oldValue, T newValue) {
      // do what you want here
    }
 }

The compiler translates the bound property x into :

 private int x;
 public int getX() {
   return x;
 }
 public void setX(int x) {
   int oldX=this.x;
   if (x!=oldX) {
     this.x=x;
     propertyChange(Point.x, oldX, x); 
   }
 }

Property Litteral and switch

Property litteral like enums can be used in a switch. This features is easy to implement if bug 5029289 (switch on strings) is implemented.

 Bean bean=new Bean();
 bean.addPropertyListener(new PropertyListener<Bean>() {
   public <T> propertyChanged(Property<Bean, T> property, T oldValue, T newValue) {
     switch(property) {
       case name:
         frame.setTitle((String)newValue);
         break;
       case value:
         slider.setValue((Integer)newValue);
         break;
     }
   }
 }

Like enums, case items are not qualified. The compiler verifies that as the variable property is typed Property<? extends Bean, T> the properties Bean.name and Bean.value exist.

The class Property

Just a preview of the methods of the class Property.

  public class Property<B, T> {
    public Class<B> getDeclaringClass() {}
    public Class<T> getType() {}
    public String getName() {}
    public boolean isReadable() {}
    public boolean isWritable() {}
    public T get(Object bean) {}
    public void set(Object bean, Object value) {}
  }

  public class Class<T> {
    public Property<T, ?>[] getProperties() {}
    public Property<T, ?> getProperty(String name) {}
  }

The signature of getProperties() is illegal with the current JLS but i hope it will be legal with the next JLS.

I will implement this spec functions of your comment, cheers
Rémi


Kitchen Sink Language and local keywords

Posted by forax on January 15, 2007 at 02:54 AM | Permalink | Comments (0)

The Kitchen Sink Language (or ksl) is open here : ksl.dev.java.net, so i hope that the next version of my prototype will be the ksl trunk.

Before trying to commit compiler patches that introduce local variable type inference or properties to the ksl trunk, i think i will write a small patch that enable the use of local keywords.

Local keywords

What is a local keyword ? A local keyword is a keyword that is only enabled at some locations in the grammar and that is considered as an identifier elsewhere.
It will ease anyone to introduce new keywords like property, indexer, dynamic or <insert your favorite keyword here>.

Just a word about properties, i have read lot of blogs about that, i have even dreamed about that this week end (a kind a nightmare in wich a property told me that she needs to be bound). So i have decided to take some rest.

Rémi



Property and interceptors

Posted by forax on January 11, 2007 at 08:10 AM | Permalink | Comments (15)

Since my last post, Cay Horstmann has recalled that properties are intended for tools and Hans Muller bid up by saying that property syntax is useless without a way to define bound properties.

Interceptors and bound properties

What Hans want is some kind of interceptor. An interceptor is an object or a method that can trap access to a property. In Java, these objects are implemented either using java.lang.reflect.Proxy or by bytecode enhancement using a VM agent or a special classloader.
It is interresting to know that bean interceptors are already defined in EJB 3 spec (JSR-220).

So for me, instead of trying to re-invent the wheel, we could perhaps transpose the concept of server side interceptors in Swing world. We 'just' need an equivalent to an EJB container for swing application. I think the concept of transaction can be borrow in the same time, it could liberate us from invokeLater and SwingWorker.

So in my opinion, adding bound properties to the language is a bad idea.
I prefer to let that job to Beans Binding experts group (JSR 295) and its leader Scott Violet.

So is property syntax usefull ?

I think that even if bound properties are not managed by the compiler, we need a property syntax at least to insert a special attribute in the bytecode that will be recognize by the reflection runtime to provide property objects at runtime.

Property interceptor by the compiler

But if you think that this kind of AOP must be done by the compiler, i propose to allow to declare two a special methods named set* and get* (the star is not a typo) that can be used instead of a particular getter or setter.

By example, a bean that declares two bound properties background and foreground in that way could be written like that :

  public class MyBean {
    public property Color background;
    public property Color foreground;

    public void set*(Property property,Object value) {
      Object oldValue=property.get(this);
      super();
      SwingPropertySupport.firePropertyChange(property,
        oldValue,property.get(this));
    }
  }

The compiler will generate foreground or background setters by duplicate the set* code for each setter.
java.lang.reflect.Property is the reflection counterpart of a property at runtime (I've just rename the Stephen Colebourne's property object to a more Java-like name), super() in that context means set the property value (pretty ugly isn't it) and SwingPropertySupport is a new class that allow to add/remove PropertyChangeListener for any property of any bean.

To Link a property to a listener, we can use

  MyBean bean=...
  SwingPropertySupport.addPropertyChangeListener(
    bean,"background",new PropertyChangeListener() {
      ...
    });

Cheers,
Rémi

P.S : to the little Peter, you can't return a gift :)



Property and bean spec

Posted by forax on January 08, 2007 at 02:20 PM | Permalink | Comments (7)

Among the questions about my property proposal and its implementation. One can be answered easily.

Why don't provide property change support ?

Because there are several ways to implement a property change support depending on what you want.

I've try to categorize them, conbinations are possible:

  • Listener and event can be at least the following couple: PropertyChangeListener/PropertyChangeEvent, VetoableChangeListener/PropertyChangeEvent, an PropertyChangeListener,/IndexedPropertyChangeEvent, or the swing lightweight ChangeListener/ChangeEvent.
  • Register/unregister listeners Listeners are stored in a collection, but which one ? A list or a set. Is the collection threadsafe, using synchronized blocks, locks or other concurrent mecanisms ? The traversal is in ascending, descending or any order.
  • Listener and thread The listener method is called by the current thread, another thread (using by example an executor) or a special thread (like the EventDispatchThread).

I hope you are convinced.

Cheers,
Rémi



All your property are belong to us

Posted by forax on January 05, 2007 at 08:01 AM | Permalink | Comments (29)

Happy new year everyone.
Since my last post, i've done some homeworks :),
and i'm please to present you a new version of the prototype java compiler which includes property support.

First, why properties ?, we have already fields and any IDE have a menu item that can generate getters and setters, so why do, we need properties ?

Why do we write getter and setter ? The reason, is that when you use a property, you don't want to know if its implementation use a field or something else. By example, you can first choose to implement it as a field and later when a new feature is require change your code to use a method. To be binary backward compatible, a carefull developer will always define a getter and a setter, even if the property is a field package visible, but its a boiler plate code and i don't see a reason why we should do that if the compiler ensure that a change in the way property is written will always be backward compatible.

The compiler must handle properties for you and garantee that implementation change must be binary compatible without writing boilerplate codes.

Defining a simple property

  public class PropertyPoint {
    property int x;
    property int y;
  }
  ...
  public static void main(String[] args) {
    PropertyPoint p = new PropertyPoint(1, 2);
    System.out.println(p.x + " " + p.y);  // replaced by p.getX(), p.getY()
  }

A word about the keyword 'property', 'property' is not a real keyword like 'public' or 'enum', so you can have a variable named property in another place in your code, i will still compile, even if you create a class property, it will still compile. Basically, if the compiler found the keyword 'property' in another place, it consider it as an identifier or a type depending on its location. This example, written by peter ahé, compiles :

  public class property { // see the name of the class ??
    public property int value; // a property
  
    // these stuffs are not properties
    property property;    // a field
    property() {          // a constructor
    }
    property property() { // a method
      return null;
    }
    property property(property property) { // another method
      return null;
    }
}

The compiler generates automatically a getter and a setter and doesn't allow developers to define their own. A property is accessed as a field (with dot) in the source code and by a getter/setter pair in the generated bytecode.

Abstract property

An abstract property is a property that is not a field thus can't be initialized by an expression. It requires the developer to write a getter and a setter. By example, i can tranform the class PropertyPoint to use polar coordinates instead of rectangular ones.

  import static java.lang.Math.*;
  public class PropertyPoint {
    abstract property double x;
    abstract property double y;
    
    property double rho;
    property double theta;
    
    public double getX() {
      return rho*cos(theta);
    }
    public void setX(double x) {
      double rho = hypot(x, y);
      theta = atan2(y, x);
      this.rho = rho;
    }
    
    public double getY() {
      return rho*sin(theta);
    }
    public void setY(double y) {
      double rho = hypot(x, y);
      theta = atan2(y, x);
      this.rho = rho;
    }
    
    public PropertyPoint(double x, double y) {
      this.x = x;
      this.y = y;
    }
}
...
    public static void main(String[] args) {
      PropertyPoint p = new PropertyPoint(1, 2);
      System.out.println(p.x + " " + p.y);  
    }

You can notice that the source of the method main doesn't change et even better, the generated bytecode doesn't change too. Another example, that mix abstract property and field :

  class Button {
    private String label;
    public abstract property String text;
    public String getText() {
      return label;
    }
    public void setText(String label {
      this.label = label;
      repaint();
    }
  }
  ...
  public static void main(String[] args) {
    ...
    Button button = new Button();
    button.text = "toto"; // replaced by button.setText("toto");
  }

Property and type

It is possible to define a property in a class or an abstract class, an interface (automatically public abstract) or an enum, but not in an annotation (currently not enforced by the prototype).
Allowed keywords for property are :
private protected public final static volatile transient.
Allowed keywords for abstract property are :
abstract private protected public synchronized final static

The current prototype has the following limitations:

  1. properties are not recognized in an already compiled code.
  2. final property support is untested.
  3. abstract property doesn't check if a getter/setter exist in the hierarchy but only in the current class.
  4. property doesn't support ':=' initialization

The current 'spec' has the following limitations:
  1. using a property in the constructor leads to an unsafe publication of this.
  2. rules about overriding property are not defined nor the reflection API

The patch againt Open JDK compiler 1.7b5:
patch-1.7b05.txt
The prototype compiler:
prototype-1.7-b05.jar

How to use the prototype ?

To enable the property syntax, call javac in this way:
java -jar prototype-1.7-b05.jar -XDallowProperty Test.java

cheers, Rémi

Continue Reading...





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