Getters & Setters vs. Public Properties

Here’s a post that I originally wrote way back in 2006, when Flex 2 was all the rage.   No, seriously, Flex 2 was awesome – it is the base of today’s Flex framework, helped to revolutionize applications on the web, and heralded the “RIA” frenzy.   The best part is that this post is still very relevant with Flex, AIR & ActionScript for mobile/web/desktop, so I decided to resurrect it from the old blog archive.  Enjoy…

I’ve been asked several times, why would you use get/set functions instead of public variables in your flex components and classes? Well, there are some great things you can do with getters and setters that you can’t do with public variables. On the other hand, there are cases where public variables may be an easy choice. When using these functions and/or public variables, the code for the caller will be the same:

mycomponent.myValue = 1;

First, lets look at public variables…

[Bindable]
public var myValue : Number

Public variables are useful when there are no addional actions that need to take place when the value has been changed. If you change the value of “myValue”, the bindings will update and everything will be handled accordingly. The value will change, and anything bound to that value will change. In this case, there is no need to use getter/setter methods, keeping code simple and easy to implement.

Now, on to getters and setters…

[Bindable(event="myValueUpdated")]
public function set myValue (value:Number):void
{
  _myValue = value;
  dispatchEvent( new FlexEvent( "myValueUpdated" ) );
}

public function get myValue ():Number
{
  return _myValue ;
}

private var _myValue : Number;

First I’ll explain the [Bindable(event=”myValueUpdated”)] statement: This indicates that the data binding to the getter’s value should be updated when the event of type “myValueUpdated” is dispatched.

You’ll notice that when the value is set, this event is dispatched, which would notify and components that are bound to this value. Using a binding event isn’t required for all getters and setters, however this approach can allow you to invoke binding events on the “getter” even if you don’t access the “setter” method.

Now, the rest… The code that I showed above is consumed in exactly the same way as a public property, but requires more code. The benefits of getter and setter functions are that they enable sequential code execution when the value is changed, and also enable inheritance in getter/setter methods.

This means that you can create your components so that specific functions are executed any time that the value is accessed using get and/or set functions.

Here’s an example:

[Bindable(event="myValueUpdated")]
public function set myValue (value:Number):void
{
  _myValue = value;
  numSets ++;
  myFunction();
  dispatchEvent( new FlexEvent( "myValueUpdated" ) );
}

public function get myValue ():Number
{
  numGets ++;
  myOtherFunction();
  return _myValue ;
}

private var _myValue : Number;
private var numGets : Number = 0;
private var numSets : Number = 0;

In this example, every time the value is set, the numSets Number is incremented, and the myFunction() function is executed. Likewise, every time the value is accessed using the “get” method, the numGets Number is incremented, and the myOtherFunction() function is executed. There is no limit to what kind of code you can execute here. You can have it dispatch custom events, change styles, create new components, etc… This turns out to be very handy when creating custom Flex components.

As I mentioned earlier, getter/setter accessors also enable inheritance on “properties” of an object. This means that you can change the behavior of a getter/setter in descendant classes, while usage remains the same. A great example of this are the “get data” and “set data” accessor methods used throughout the Flex framework (and part of the IDataRenderer interface). You can override “get data” or “set data” methods to modify behaviors and/or return values, without changing how those methods are used.

  • Craig Drabik

    I see a lot of developers improperly creating bindable read-only getters (i.e. no setters). You can follow the above example putting the bindable metadata on your getter and dispatching the named event any time your code wants to publish an updated value :

    [Bindable(event=”myEventName”)]
    public function get myValue():Number
    {
    //return something
    }

    override protected function commitProperties():void
    {
    super.commitProperties();
    if (myValueChanges)
    {
    //Trigger bindings
    dispatchEvent(new Event(“myEventName”));
    }
    }

  • http://histos.net Cliff Meyers

    I also like putting an if block in the setter that ensures the logic will only be executed if the value has actually changed:

    if (_myValue == value)
    return;

  • http://twitter.com/as3isolib as3isolib

    Wow! we have two of former TLs here :)

    I tend to favor what Cliff said above, using the boolean check to save on processing same values. Another benefit of the getter/setter paradigm is the enforcement through interfaces. Simple properties are not enforceable via interfaces unless you do a pseudo abstract class kinda like this – http://bit.ly/oDrz7u

    Glad I stumbled onto your blog, I will be RSS’ing this. Later, Justin

  • http://histos.net Cliff Meyers

    Craig and I had an interesting discussion offline about the “equality check” I mentioned in my comment. Craig pointed out that if you use [Bindable] on a getter (with a matching setter) without specifying an event name, mxmlc will generate a special class which overrides the behavior in the setter and performs the equality check for you. However, if you are using [Bindable] with a custom event type, the class isn’t generated at all and such logic needs to be implemented by the developer.