Thursday, November 15, 2007

ActionScript 3.0 get/set Accessors: A Peek At Java 7 Properties?

ActionScript 3.0 supports classes with methods and data members in a very similar fashion to how Java supports classes, methods, and data members. In addition, ActionScript supports the concept get/set accessors that feel like the mashing together of traditional accessor methods with data members. This post is intended to provide an overview of ActionScript's special get/set accessors for those coming to ActionScript from Java. In addition, this post may be of interest to those wondering how the much discussed properties would be supported in Java 7 because such an addition would likely share characteristics with ActionScript's get and set accessors.

The following code listing (AccessDemonstrator.as) shows an ActionScript class that makes use of class data members, class methods, and get and set accessors.


package
{
/**
* This class provides examples of using properties, methods, and accessors.
* It is intentionally placed in an anonymous package to make compilation
* trivial (file can be co-located with consuming MXML file).
*/
public class AccessorDemonstrator
{
private var privateVariable:String = "Private Variable";
private var privateVariable2:String = "Another Private Variable";
public var publicVariable:String = "Public Variable";

/**
* Provide my privateVariable.
*
* @param My private variable.
*/
public function getPrivateVariable():String
{
return privateVariable;
}

/**
* Set my private variable.
* @param aNewPrivateVariable Value to set my private variable to.
*/
public function setPrivateVariable(aNewPrivateVariable:String):void
{
privateVariable = aNewPrivateVariable;
}

/**
* Access my privateVariable.
*
* @return My private variable.
*/
public function get privateVariableA():String
{
return privateVariable;
}

/**
* @private
*/
public function set privateVariableA(aNewPrivateVariable:String):void
{
privateVariable = aNewPrivateVariable;
}

/**
* Provide my privateVariable2.
*
* @return My private variable 2.
*/
public function get privateVariableB():String
{
return privateVariable2;
}
}
}


I highlighted the get and set keywords in the above code listing. Note that ActionScript still supports traditional get and set methods (not highlighted) and that the get/set accessors are a special addition. It is difficult to ascertain much difference between the traditional get/set methods and these special get/set access methods from the code listing above. However, the code that uses this class makes the difference more obvious. Here is some simple MXML code (AccessorsRevealed.mxml) that uses the above ActionScript class.


<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
xmlns:flash.display="flash.display.*"
width="750" height="500"
applicationComplete="tryThem();">

<mx:Script>
<![CDATA[
/**
* To compile solely this Flex application from the command line, use
* mxmlc -debug=true -strict=true AccessorsRevealed.mxml
*
* This application demonstrates ActionScript accessors and contrasts them
* with regular ActionScript properties and methods.
*/

import AccessorDemonstrator; // Class with accessor examples.

private const accessorExample:AccessorDemonstrator = new AccessorDemonstrator();

private function tryThem():void
{
/*
// This call commented out because it will NOT compile and mxmlc compiler
// reports this error:
//
// Error: Attempted access of inaccessible property privateVariable
// through a reference with static type AccessorDemostrator.
//
// (this is because of attempt to access a private property directly).
logToTrace( "private variable (directly) = "
+ accessorExample.privateVariable );
*/

logToTrace( "private variable (get method) = "
+ accessorExample.getPrivateVariable() );

logToTrace( "public variable (directly) = "
+ accessorExample.publicVariable );

accessorExample.privateVariableA = "Private Property";
logToTrace( "private variable (accessor) = "
+ accessorExample.privateVariableA );

/*
// This section is commented out because no 'set' accessor was provided for
// this property. If this was not commented out, the following compiler
// error message would be reported:
//
// Error: Property is read-only.
//
accessorExample.privateVariableB = "Another Private Property";
*/
logToTrace( "private variable 2 (accessor) = "
+ accessorExample.privateVariableB );
}

/**
* Log provided message to trace() with this class's name prefixing the output.
* @param aStringToLog String message to be logged to trace().
*/
private function logToTrace(aStringToLog:String):void
{
trace( "AccessorDemonstrator - " + aStringToLog );
}
]]>
</mx:Script>

<mx:HBox id="mainBox">
<mx:Text text="See trace() output." />
</mx:HBox>

</mx:Application>


I commented out some of the script code in the MXML snippet above because it would not compile if not commented out. I included explanation of what errors would result from that code. These examples prove that ActionScript hides private class data members from clients and forces access to them via public methods or accessors.

Even more interesting is the syntax used to access class methods versus the syntax used to access get/set accessors. The method approach calls the full method name exactly as done in Java. The accessor, on the other hand, is called directly without parentheses and reads like it is direct property access. Note that the set and get accessor methods had to be named different than the data members they returned so that their use would not be ambiguous.

I also intentionally left out a "set" for one of the data members to show how the compiler then enforces that this particular property is read-only.

The Flex debugger trace() output is shown in the next image (click on the image to enlarge it):



Some of the documentation related to ActionScript calls data members "properties." I like to instead call them data members and think of "properties" as the combination of a data member with a get and/or set accessor. In fact, when you look at the ASDoc-generated Flex 2 Language Reference, you can see in the "Implementation" section of various class' "properties" that they (the properties) are implemented with get/set accessors.

For example, the Flex 2 Language Reference for Panel's title property shows its implementation as public function get title():String and public function set title(value:String). This indicates that get and set accessor methods are how the title property is implemented for Panel. So, when a user writes code like myPanel.title = "A Panel Title";, there is a specially marked "set" method being called. Likewise, if the user writes code like trace(myPanel.title);, there is a specially marked "get" method that is invoked.

Just as I only defined a get and not a set for one of my data members above, some of the Flex classes have read-only properties via the same implementation. For example, Accordion's contentHeight property is read-only because only the get accessor is defined.

One can of course, provide the same differentiation between read-only (no set accessor), write-only (no get accessor), or read-write (get and set accessor) without special accessor methods. In both ActionScrip and Java, this is possible with public get and set methods. The difference with these special get and set accessors is the client syntax used to access the properties. With the special get and set keywords, the client code does not need to call getXXXXX and setXXXX methods, but can instead simply access the "properties" directly.

I plan to discuss the advantages of the get and set accessors as opposed to get and set methods in a separate blog and use that discussion to cover the potential of Java 7 adding the properties concept to the language. However, whether one likes or dislikes the idea of Java adding properties in Java 7, ActionScript's implementation of the concept gives us an idea of what they might provide.

In many ways, ActionScript's accessors are syntactic sugar. Most of what they support can be done with the more traditional getXXXX and setXXXX methods. The ActionScript documentation talks about advantages of the get and set accessors including information hiding and encapsulation (available with the traditional getXXXX and setXXXX methods). The documentation also adds that the get/set accessors are superior to traditional get and set methods because the get/set accessors are easier for the client to call, provide a single interface to the user, and don't have the "unwieldy names" of the traditional get and set accessors. These are all minor advantages that are nice and may as well be used because they already exist in ActionScript. However, I am not sure these advantages are compelling enough to justify adding to Java with so much legacy software already using the traditional get/set mechanisms (introspection for example). All this being stated, I have enjoyed other Java syntactic sugar like the String.isEmpty(). I'll leave additional discussion of Java 7 properties for a later blog entry.

A nice introduction to writing classes in ActionScript 3.0 is available in "Flash Quick Start: Creating a Simple ActionScript 3.0 Class." A concise but thorough overview of the get/set accessors in ActionScript is available in the blog entry Qwick Thoughts: Get/Set in ActionScript 3 Explained.

1 comment:

@DustinMarx said...

There is an interesting comparison of properties implementations in different programming languages at http://oslo.cs.sjsu.edu:8080/xwiki/bin/view/JavaProperties/PropertiesInOtherLanguages.