Friday, December 19, 2008

JavaScript Virtual Properties

Some programming languages have a particular feature that I find very useful. This feature allows a setter method to disguise itself as a variable assignment. For example, instead of:

person1.setAge(42);

You would do this:

person.age = 42;

Under the covers, it's actually not setting a variable (as it appears) but rather it's calling a setter method.

The same language feature allows a getter method to disguise itself as a variable read. For example, instead of:

print( person1.getAge() );

You would do this:

print( person1.age );

Again, under the covers, we are actually not setting a variable (as it appears) but rather we are calling a getter method.

Virtual Properties


The above described language feature does not have an industry standard name (that I know of). The old VB used to call it "property procedure". I've heard it called "getters and setters", but that is a confusing term because languages like Java have "getters and setters" but they do NOT have the above mentioned language feature. C# calls them properties. But this is also a confusing term. JavaScript and Java both use the term property to mean something different. Also, many people use the term property interchangeably with "field" or "instance variable". Ruby uses the term "attr_accessor".

But JavaScript (as of ECMAScript 4th edition) will soon be supporting this feature. And they use the term "Virtual Property" which makes the most sense to me. So that is what I will use. To be more specific, ECMAScript 4 defines three terms:

Value Property: A value property is the new name for what used to be called "property" (without the "value" prefix). Value properties are just plain old instance variables (aka fields). The reason for the new term is to distinguish a value property from a "virtual property".

Virtual Property: A virtual property is really a getter and/or setter method that (to the caller) appears to be an instance variable.

Property: The term "property" is now inclusive of both value properties and virtual properties. Thus, clients of the object just see "properties" there is no way they can tell whether they are accessing a virtual property (i.e. calling a setter or getter method) or accessing value property (i.e. a variable). The fact that the caller is hidden from these details is really the whole point of virtual properties.

Why Use Virtual Properties


You may be asking yourself, "why would I want to use this feature?" Well let me explain by reviewing setter/getter methods in general.

Most of the time, setter methods (the old kind of setters and the new "virtual property" style setters which I will show shortly) don't do much that is interesting. They usually, just turn around and set a variable:

function setAge(newValue){
this._age = newValue;
}

But sometimes, the setter adds a bit of value beyond merely setting an instance variable. For example, validation:

function setAge(newValue){
if(newValue) > 150) throw new Error("Too Old");
this._age = newValue;
}

Or perhaps the setter may trigger some other action (or side effect):

function setAge(newValue){
this._age = newValue;
recalculateDateOfBirth();
}

And sometimes the setter has no corresponding underlying instance variable at all. For example, storing age and dateOfBirth is redundant. So you may have:

function setAge(newValue){
this.dateOfBirth = computeDateOfBirthFromAge(newValue);
}

But the vast majority of the time, setters just set a variable:

function setAge(newValue){
this._age = newValue;
}

This results in a whole ton of boiler plate code for setter methods. The same is true of getter methods, some times they do something interesting like this:

function getArea(){
return this._length * this._width;
}

But most of time they just do the same old boring thing, return the value of a variable:

function getLength(){
return this._length;
}

Again, this results in a ton of boring, noisy, boiler plate code. In fact, most modern IDE's have a shortcut called "generate getters and setters".

So now, with virtual properties, any time you have a setter or getter that does nothing but set or get the value of an instance variable, just get rid of it. Instead allow direct access to the instance variable.

The payoff: all those boilerplate do-nothing getters and setters just go away!

How to Create a JavaScript Virtual Property


So now in JavaScript you have two new keywords: get and set. These are placed write after the word function like this:

function get age() {
return this._age
}

function set length(newValue) {
if(newValue > 150) throw new Error("Too Old");
this._age = newValue
}


Browser Support


As it turns out Safari, FireFox and Opera all support virtual properties. And now (from what I have read), virtual properties will be supported in IE8.

More Info


Mozilla: Defining Getters and Setters
Cedric on gettersand setters
ECMAScript 4 Look for section titled: Property States

No comments: