Monday, May 12, 2008

Get smart with properties in Scala

Properties are easy to declare in Scala

class ShoePhone
{
    var vibrateOn = false
    var volume = 8
}


What does this really mean?

Here is the same code, written in a more cluttered way, illustrating the setters and getters which are automatically generated above
class ShoePhone
{
    private[this] var _vibrateOn: Boolean = false;
    private[this] var _volume: Int = 8;

    def vibrateOn: Boolean = _vibrateOn;
    def volume: Int = _volume;

    def vibrateOn_=(on: Boolean)
    {
        _vibrateOn = on;
    }

    def volume_=(vol: Int)
    {
        _volume = vol;
    }
}
Here the private fields are given names with an added underscore prefix. These names could be anything. This is just a convention I'd like to see. I don't like seeing a lot of one-off names (such as the ones I used for the setter method parameters, on and vol). If there is a simple way to eliminate the one-off names akin to what one finds in the Java idiom
this.volume=volume;
please let me know.

The getter methods are defined without parentheses so they appear in code just as if they were fields. See previous post on the Uniform Access principle.

The setter methods are defined by adding
_=
This suffix creates the method used when a variable is assigned using
=
Say we have a ShoePhone instance shoePhone and set its volume
shoePhone.volume = 0
You could write to the same effect
shoePhone.volume_=(0)

For an explanation of the access modifier private[this] see The Scala cone of silence.



----------------
Now playing: Yeasayer - 2080
via FoxyTunes

Version 1.1 (correction)

Update (May 22, 2008): Using the Java Class File disassembler javap on the ShoePhone class file, you can see what Scala does behind the scenes in the Java bytecode
javap -private ShoePhone

Compiled from "ShoePhone.scala"
public class com.control.equipment.ShoePhone extends java.lang.Object implements scala.ScalaObject{
    private int volume;
    private boolean vibrateOn;
    public com.control.equipment.ShoePhone();
    public void volume_$eq(int);
    public int volume();
    public void vibrateOn_$eq(boolean);
    public boolean vibrateOn();
    public int $tag();
There are private fields and public getter methods which use the same name. The setter method adds the suffix  _=  cryptically rewritten as  _$eq  to comply with Java naming rules.

If your setter method needs to do something special, you can always define it explicitly
class ShoePhone
{
    var _vibrateOn = false

    private[this] var _volume = 8

    def volume = _volume

    def volume_=(__volume: Int)
    {
        assert(__volume>=0)
        assert(__volume<=8)
        _volume = __volume;
    }
}
where I've used an underscore prefix to distinguish the private variable from the public getter method, again to avoid one-off names. I've used two underscores for the explicit setter method parameter. The use of underscores at the beginning of names is discouraged in Java. If anyone knows a better, less discouraged, more aesthetic way to do this, please let me know.

Update (May 23, 2008): If you need your ShoePhone available as a JavaBean, it's easy. Just use the annotation @scala.reflect.BeanProperty.
class ShoePhone
{
    @scala.reflect.BeanProperty
    var vibrateOn = false

    @scala.reflect.BeanProperty
    var volume = 8
}
The setters and getters will then be generated automatically for you by the Scala compiler.
javap ShoePhone

Compiled from "ShoePhone.scala"
public class com.control.equipment.ShoePhone extends java.lang.Object implements scala.ScalaObject{
    public com.control.equipment.ShoePhone();
    public void setVolume(int);
    public int getVolume();
    public void setVibrateOn(boolean);
    public boolean isVibrateOn();
    public void volume_$eq(int);
    public int volume();
    public void vibrateOn_$eq(boolean);
    public boolean vibrateOn();
    public int $tag();

No comments: