Wednesday, August 27, 2008

Bound properties in Scala

I've been doing some GUI programming in Scala recently. Following the bean conventions in Java, I tend to require three things of each property I have on an object that will be used in a GUI:
  1. A getter method.
  2. A setter method.
  3. A listener / notification mechanism for when the property changes.
The getters and setters are required for encapsulation, so that the internal representation of the properties of an object implementation can be changed without affecting the properties themselves. The notification mechanism is required for a GUI, so that one or more components that display the property can be updated when it changes.

The key problem with the ad-hoc implementation of properties (as in JavaBeans) is that they tend to make classes noisy, with all of the getX(), setX() stuff, and the listener mechanism. Things become even more complicated when properties take on the nature of collections, where multiple objects can conceptually be added or removed.

In a search for simplicity, I have been investigating JavaFX and the even more impressive ScalaFX. However, JavaFX does not yet allow bindings to properties implemented in a Java model, and ScalaFX, although very promising, is not quite ready for prime time. (It's more the potential for bugs I can't understand rather than API changes that have put me off ScalaFX for the time being.)

Until ScalaFX is ready, I have found a neat stop-gap solution. Inspired by the Scala wiki entry on Properties, I have set up my own properties as follows:
My Properties extend scala.swing.Publisher so it's possible to listenTo them for events. I defined a PropertyChanged event that is intended to be fired when a property changes. The properties also have apply() and update() methods which act as getters and setters respectively.

So, what advantages do these kinds of properties have over normal getX(), setX() and a listener mechanism?

Firstly, the contract of a property is clearly defined. There is no bean-like assumption that a setX() method on a class is related to a corresponding getX() method, nor that a particular event will be fired when a change occurs.

Secondly, each property is nicely modularized. Properties often refer directly to a value stored in a class, and it's easy to define a ValueProperty which performs this automatically. Then, for the enclosing class, you can write something like this:
Instead of something like this:
At first glance, the properties version of x may appear to break the principle of encapsulation, but it doesn't. If, in the future, I wish to change the implementation of x, I could do something like this:
Clients of the code will then be able to use the x property in the same way they always did.

This method of defining a clear contract for a property can also be extended to vector properties, in which the property contains a collection. It can be done fairly generally, so that the collection property may be backed in various ways by pre-existing collections (in the same way that you could implement a Map as a HashMap or a TreeMap or whatever).

A final advantage of these properties arises when they are bound into a GUI. For example, I have a text field derivative called BoundIntField which displays an integer value. To create an instance of this class, bound to property x I do the following:
And... that's it! The BoundIntField automatically listens for changes to x and updates itself. Also, when BoundIntField loses focus or receives an enter key press, it updates x. This is all done without breaking encapsulation, and without me having to write any duplicate glue code at all!

No comments:

Post a Comment