Monday, July 2, 2007

Get/Set in ActionScript 3 Explained

Introduction

If you have seen ActionScript 3 in Flash CS3 or Flex 2, you may have noticed the get and set statements. Correctly written, these statements follow this format (minus ASDoc comments and bindable metadata tags):

public function get name():String {
return _name;
}

public function set name(value:String):void {
_name = value;
}
Note that the private class variable is _name. This is a standard for get/set methods and somewhat a standard for any private variable in Flex. The underscore (_) is required because the functions are named the same as the variable and the compiler (and those viewing the code) would be confused as to which was being referenced.

Naming the set parameter "value" is a common practice and works well when renaming variables.


What Do get/set Offer?

They act as if the class had a public variable but allow you to do more. If this is to be a read-only property, simply provide only the get function. If this is to be a write-only property (rare), simply provide only the set function. You may also write code to do additional work such as log something, check permissions, set a different variable, or do extra business logic.


ASDoc get Methods

It is a little odd to ASDoc these methods. Remember Get methods should come before set methods. The get should be documented with a short explanation of what the variable represents.
/**
* The first name provided by the credit card
*/
private function get firstName():String {
return _firstName;
}
Remember, just like in Java, documentation of the "firstName" property of the "Person" class shouldn't say "The first name of the person". Offer something more to the reader. Where could the first name come from (credit card, typed by person, typed by customer service agent, parsed from fullName)? What letters could it contain? Could a middle initial exist here?


ASDoc set Methods

Documenting the set methods is a little different. Since the meaning of the variable was explained in the get, it does not need to be repeated in the set. To accomplish this, mark the set as private in the ASDoc.
/**
* @private
*/
private function set firstName(value:String):void {
_firstName = value;
}
This will produce one comment in the generated documentation.

See the livedocs reference for more information:

http://livedocs.adobe.com/flex/201/html/wwhelp/wwhimpl/common/html/wwhelp.htm?context=LiveDocs_Book_Parts&file=asdoc_127_9.html


Bindable get/set Methods

Normally, I mark the class as Bindable so all get/set methods are marked as bindable. It does so with an event named "variableChange" where variable is the get/set method name. Simply putting [Bindable] just above your class definition will accomplish this.

If you need more control, you may write the following at the top of your get method (assuming this is the firstName property):
[Bindable(event="firstNameChange")]
This works the same for public variables. See livedocs for more information:

http://livedocs.adobe.com/flex/201/html/wwhelp/wwhimpl/common/html/wwhelp.htm?context=LiveDocs_Book_Parts&file=asdoc_127_9.html


In Other Languages

Java uses getFirstName() and setFirstName() functions which can be generated by NetBeans using the "refactor" option (also has a keyboard shortcut). They don't name the private variables differently because there is no need. The parameter for the setFirstName is typically the same as the private variable and is assigned by stating: this.firstName = firstName;

VB6 had the get/set functionality in the form of: public property let, public property set, and public property get. Where let was by value and set was by reference (for Objects).

I'm sure there are plenty of other implementations.


My 2 Cents

I use these for every private variable; however, it is much easier to have a public variable and change it to private scope and write get/set functions later if you ever need to do more processing or if you like the ASDoc output better. This does not change the API for the class and allows it to be written much faster.

I like the Flex method the best for simple getters/setters; however, if the function does more work than meets the eye, it should be written as normal get/set methods. This allows you to provide more parameters and alerts users of the class that it may do some additional processing.

10 comments:

Unknown said...

Nice explanation. Some other things that might interest you. You can define get/set functions in an interface. Also, the syntax is actually most similar to C#. Taking your example in C# it would be

public String name {
get : { return _name;}
set : {_name = value;}
}

In C# the value param name is implicit on the set method.

Graeme Wicksted said...

I wish get/set was that simple in Flex and would auto-create the events for me! =)

Unknown said...

@Michael. A small correction. In C#, the example would be:

public String name {
get { return _name;}
set {_name = value;}
}

Or, using the new syntax:

public String name {
get; set;
}

Anonymous said...

Nice post, I've been using a combined get/set method.
so for instance if you had an object Car, with a parameter _price instead of getting it with: myCar.getPrice(); and setting it with myCar.setPrice(15000.0); you can do the following:

var carPrice:Number = myCar.price();

carPrice += 1000.0;

myCar.price(carPrice);


the method in the Car class would be:

public function price(value:Number = -1):Number
{
if (value == -1)
{
return _price;
}
else
{
_price = value;
return _price;
}
}

in the above method I've used -1 as the default parameter because I would never pass it into the function. You just need to set up the default parameter with a logically impossible value and then you're sweet :)

~ Jazz

Graeme Wicksted said...

Hi Anonymous, I would not advise using a method like that but what works for you is what matters.

Note: you could create public variables then change them to get/set later if you need to modify the functionality.

In AS3, no other classes will need to change how they access the variable if you do this.

Owen Eustice said...

Rewrite the example with the ActionScript style will be as follows:

public function set type(carType:String):void{
this.carType = carType;
}

public function get type():String{
return carType;
}

The advantage of this approach is that it allows you to avoid the traditional accessor functions with unwieldy names, such as getCarType() and setCarType(). Another advantage of getters and setters is that you can avoid having two public-facing functions for each property that allows both read and write access.

http://ntt.cc/2009/07/26/beginning-actionscript-3-super-this-setter-getter.html

Steve Penza said...

Sometimes it would be nice if you could pass a getter as a method parameter the same way you can pass a function...

Graeme Wicksted said...

I agree Steve. This was also annoying when working with Delegates in C# as getters were not allowed. See here for more info: http://geekswithblogs.net/akraus1/archive/2006/02/10/69047.aspx

DannyStaple said...

It is a shame that there is a half backed version of this only in As2. Get/set property signatures can NOT be used in AS2 interfaces. Before you ask - it is because of specific hardware that is only as2 compatible that I am not using As3.
Two questions: Anybody found a way to do this in As2?
And can you put those into an interface in AS3 though?

Graeme Wicksted said...

Looks valid to do get/set in interfaces (according to IntelliJ - haven't tried a compile):

function get myString():String;

function set myString(value:String):void;