Enumerations With Class

3 May 2009

 

References:
Prog  ActionScript 3.0 – Enumerations with Classes:
http://livedocs.adobe.com/flex/201/html/wwhelp/wwhimpl/common/html/wwhelp.htm?context=LiveDocs_Book_Parts&file=04_OO_Programming_161_07.html

http://www.herrodius.com/blog/87

http://www.barneyb.com/barneyblog/2007/11/02/enums-and-actionscripts-static-initializers/

Environment:
ActionScript 3.0; Flex Builder 3.0 with Flex SDK 3.2

Keywords:
ActionScript 3.0,  Enumerations with Classes, private constructor, singleton, static code block

Enumerations:

ActionScript  3.0 documents suggest the use of  classes with only static constants as a way to create enumerations.

The first approach uses variables of basic types such as String, int, or uint within a class.  In fact, Flash API use this approach, as in the following code, we are told:

public final class PrintJobOrientation
{
    public static const LANDSCAPE:String = "landscape";
    public static const PORTRAIT:String = "portrait";
}

The  second approach involves a separate class with static properties for the enumeration:  Here, each static property is an instance of the class and thus allows improved type checking. The example provided is as follows:

public final class Day
{
    public static const MONDAY:Day = new Day();
    public static const TUESDAY:Day = new Day();
    public static const WEDNESDAY:Day = new Day();
    public static const THURSDAY:Day = new Day();
    public static const FRIDAY:Day = new Day();
    public static const SATURDAY:Day = new Day();
    public static const SUNDAY:Day = new Day();
}

An example usage is as follows:

function getDay():Day
{
    var date:Date = new Date();
    var retDay:Day;
    switch (date.day)
    {
        case 0:
            retDay = Day.MONDAY;
            break;
        case 1:
            retDay = Day.TUESDAY;
            break;
        case 2:
            retDay = Day.WEDNESDAY;
            break;
        case 3:
            retDay = Day.THURSDAY;
            break;
        case 4:
            retDay = Day.FRIDAY;
            break;
        case 5:
            retDay = Day.SATURDAY;
            break;
        case 6:
            retDay = Day.SUNDAY;
            break;
    }
    return retDay;
}

Note that the return type is Day; this is how enhanced type checking comes into play.

Exercise for the Reader: Enhancing the Day Class Sample

Adobe documentation suggests an exercise for the reader: enhance this class by associating an integer with each day, as well as a string representation. Here is my solution:

package
{
    public class MyDay
    {
        private var _dayNum:int;
        private var _dayStr:Array = ["Sun","Mon","Tues","Wednes","Thus","Fri","Satur"];

        public static const SUNDAY:MyDay    = new MyDay(0);
        public static const MONDAY:MyDay    = new MyDay(1);
        public static const TUESDAY:MyDay   = new MyDay(2);
        public static const WEDNESDAY:MyDay = new MyDay(3);
        public static const THURSDAY:MyDay  = new MyDay(4);
        public static const FRIDAY:MyDay    = new MyDay(5);
        public static const SATURDAY:MyDay  = new MyDay(6);
        public function MyDay(dayNum:int)
        {
            _dayNum=dayNum;
        }
        public function get dayNum():int
        {
            return _dayNum;
        }
        public function get dayStr():String
        {
            return _dayStr[_dayNum]+”day”;;
        }
        public function toString():String
        {
            return dayStr;
        }
    }
}
class SingletonEnforcer {}

I had intended to use class  SingletonEnforcer to restrict the use of  MyDay constructor to this package,  since I cannot make the MyDay constructor private; but that leads to TypeError 1115. According to http://www.herrodius.com/blog/87 , it is impossible to call the constructor of the inner class (i.e. SingletonEnforcer) in a static member of the top class. 

The alternative is to use an unnamed  static code block:

private static var _enumsInited:Boolean = false;
//unnamed static code block
{
    _ enumsInited = true;
}

and  then modify the constructor; the final code is as follows:

package
{
    public class MyDay
    {
        private var _dayNum:int;
        private var _dayStr:Array = ["Sun","Mon","Tues","Wednes","Thus","Fri","Satur"];

        public static const SUNDAY:MyDay    = new MyDay(0);
        public static const MONDAY:MyDay    = new MyDay(1);
        public static const TUESDAY:MyDay   = new MyDay(2);
        public static const WEDNESDAY:MyDay = new MyDay(3);
        public static const THURSDAY:MyDay  = new MyDay(4);
        public static const FRIDAY:MyDay    = new MyDay(5);
        public static const SATURDAY:MyDay  = new MyDay(6);
        private static var _enumsInited:Boolean = false;
        //unnamed static code block
        {
            _enumsInited = true;
        }
        public function MyDay(dayNum:int)
        {
            if (_enumsInited)
                throw new Error("[MyDay] The enum is already inited.");

            _dayNum=dayNum;
        }
        public function get dayNum():int
        {
            return _dayNum;
        }
        public function get dayStr():String
        {
            return _dayStr[_dayNum]+”day”;
        }
        public function toString():String
        {
            return dayStr;
        }
    }
}

This works, because the static code is executed after all static members have been set!

From
http://www.barneyb.com/barneyblog/2007/11/02/enums-and-actionscripts-static-initializers/

In a nutshell, a static initializer is kind of like a constructor, but it’s for the class object itself, not instances of the class. It gets invoked during classloading, after all static properties have been set, but the class is turned loose for general consumption.

Here is the code where I exercised the above classes Day and MyDay:

package {
    import flash.display.Sprite;

    public class EnumClassAS3 extends Sprite
    {
        public function EnumClassAS3()
        {
            var dayOfWeek:Day = getDay();
            trace (dayOfWeek);
            //Today is (was) Saturday:
            if (dayOfWeek == Day.SATURDAY) {
                trace("[Day] SATURDAY");
            }
            else {
                trace("[Day] Not SATURDAY");
            }
            var strDay:String;
            switch (dayOfWeek)
            {
                case Day.SATURDAY:
                    strDay="Saturday"
                    break;
                default:
                    strDay="Not Saturday";
                    break;
            }
            trace("[Day] strDay:" + strDay);
            var myDay:MyDay = getMyDay();
            trace("[MyDay] dayNum:"+ myDay.dayNum );
            trace("[MyDay] toString:"+myDay);
            trace("[MyDay] dayStr:"+ myDay.dayStr );
            if (myDay == MyDay.SATURDAY) {
                trace("MyDay is: " +"SATURDAY");
            }
            else {
                trace("MyDay is NOT: " +"SATURDAY");
            }
            var myOtherDay=getMyDay();
            if (myOtherDay == MyDay.SATURDAY)
                trace("MyOtherDay is: " +"SATURDAY");
            if (myOtherDay == myDay)
                trace ("SameDay");
            if (myOtherDay === myDay)
                trace ("SameStrictDay");
            var extraDay:MyDay=new MyDay(8);
        }
        private function getDay():Day
        {
            var date:Date = new Date();
            var retDay:Day;
            switch (date.day)
            {
                case 0:
                    retDay = Day.SUNDAY;
                    break;
                case 1:
                    retDay = Day.MONDAY;
                    break;
                case 2:
                    retDay = Day.TUESDAY;
                    break;
                case 3:
                    retDay = Day.WEDNESDAY;
                    break;
                case 4:
                    retDay = Day.THURSDAY;
                    break;
                case 5:
                    retDay = Day.FRIDAY;
                    break;
                case 6:
                    retDay = Day.SATURDAY;
                    break;
            }
            return retDay;
        }
        private function getMyDay():MyDay
        {
            var date:Date = new Date();
            var retDay:MyDay;
            switch (date.day)
            {
                case 0:
                    retDay = MyDay.SUNDAY;
                    break;
                case 1:
                    retDay = MyDay.MONDAY;
                    break;
                case 2:
                    retDay = MyDay.TUESDAY;
                    break;
                case 3:
                    retDay = MyDay.WEDNESDAY;
                    break;
                case 4:
                    retDay = MyDay.THURSDAY;
                    break;
                case 5:
                    retDay = MyDay.FRIDAY;
                    break;
                case 6:
                    retDay = MyDay.SATURDAY;
                    break;
            }
            return retDay;
        }
    }
}

Flex Builder 3 Tips

28 April 2009

 

Debugging: Using Standalone Flash Player

Are you tired of waiting for the browser to launch after starting your debugging session? Then, you should use the debug version of the standalone Flash Player. To do so:

  • right click on your project in the Flex Navigator,
  • select “Properties” and in the resulting dialog (see below),
  • choose the “ActionScript Compiler” entry on the left sidebar,
  • uncheck :Generate HTML wrapper file.

You are now set to use the standalone Flash Player. If you do not have the debug version of the Flash Player, which is required for this option, Flex Builder will inform you.

Adobe sites have tools to tell you what version of Flash Player you have and the debug standalone player as well.

You can go back to using the browser by checking “Generate HTML wrapper file.”

HTMLWrapper

Insight into AS3 Indexed Arrays

27 April 2009

Haluk Ozdemir – April 2009

Insight into AS3 Indexed Arrays

References:

Literals:
http://livedocs.adobe.com/flex/3/html/help.html?content=03_Language_and_Syntax_13.html

TypedArray implementation:
http://livedocs.adobe.com/flex/3/html/10_Lists_of_data_7.html#126815

as3corelib:
http://code.google.com/p/as3corelib/

ArrayCollection:
http://www.adobe.com/devnet/flex/
learn/content/flp_adobetraining_f3as3_arraycollections.html

http://blog.flexdevelopers.com/labels/Jeremy%20Mitchell.html
http://blog.flexdevelopers.com/2009/03/flex-basics-arraycollection.html

Demo of as3corelib’s ArrayUtil class:
http://ntt.cc/2008/09/01/as3corelib-tutorial-how-to-use-arrayutil-class-in-flex.html

ArrayUtilities Class from ActionScript 3.0 Cookbook
http://rightactionscript.com/ascb.
Contains the duplicate() utility; samples can be found in ActionScript 3.0 Cookbook, O’Reilly, 2007.

Essential Actionscript 3.0, O’Reilly, 2007.

Related Reading:

 

Overview

An array – using the term array in its generic sense – is a container for a set of items. Flex supports the following types of arrays:

Indexed arrays use (unsigned) integers to identify the individual entries; we generally refer to an indexed array simply as array. Indexed arrays are implemented by the Array class:

	var myArray:Array=new Array();
	myArray[1]=”apple”

Associative arrays, also called hashes,

use strings to identify the individual entries; in other words, associative arrays contain named elements instead of numbered elements.

Associative arrays are implemented by the Object class.

	var myMap = new Object();
	myMap[“name”]=”John”

Although Flex allows associative arrays to be constructed using Array class constructor, the resulting object does not have access to the Array class methods or properties.

Dictionaries use objects to identify individual entries; the entries are more commonly referred to as key, value pairs. Dictionaries are implemented by the Dictionary class.

[ ] is known as the array access operator.

Indexed Arrays

· Each value can be accessed using an unsigned 32-bit integer, using the array access operator [ ].

· Arrays are not typed; one does not declare, for instance, an array of int’s or strings. In fact, the values can be of mixed data type:

	myArray[1]=”apple”;
	myArray[2]=20.0;

· Arrays are sparse arrays: there may be an element at index 0 and another at index 9, but nothing in between those two elements. In this case, the elements in positions 1 through 8 are “undefined”, indicating the absence of elements.

· Array is a dynamic class; when deriving classes from Array, the derived class must also be declared dynamic:

	public dynamic class TypedArray extends Array
	{
		. . .
	}

· Array inherits from Object.

Creation using Array class constructor:

· Using the default constructor, we create an array of length zero:

	var myArray= new Array(); //length is 0


· We can also specify the length when creating the array using the constructor:

	var myArray=new Array(10); //length 10; values “undefined”

The array size will increase to accommodate new values as they are added; the length property tells us the size of the array. The length property can also be set to increase or decrease the array length; setting length equal to zero clears the array.

· Another way to create an indexed array is to provide the initial values in the constructor:

	var myArray:Array = new Array (”apple”, 20.0);


· In MXML, you can create an array as follows:

	<mx:Array id="mxArrayInt">
		<mx:int>0</mx:int>
		<mx:int>1</mx:int>
	</mx:Array>

Creation using Array Literals:

Array literals are enclosed in bracket characters ([]) and use the comma to separate array elements, as in: [“apple”, 20.0] .

Array lterals can be used to create and initialize an Array:

	// Assign literal directly; note no ”new”
	var myArray:Array=[];
	var myArray:Array = [”apple”, 20.0];

Tracing Arrays:

The toString() method of the Array class returns a string that represents the elements in the specified array, with “,” as the separator.

The trace() function can be used directly without first calling toString(), as the toString() method will be automatically invoked for you.

The join() method also returns a string, but allows one to specify the separator; the specified separator can be any object, and its string value is used as the separator.

The split() method of the String class splits a String object into an array of substrings by dividing it wherever the specified delimiter parameter occurs; in other words, one can join() and then split() to get back the array.

Array Operations:

We can use arrays as stacks (LIFO):

  • push(): uint method will add an element at the end; returns the new length of array. push() takes variable number of args.
  • pop (): * method will retrieve the element from the end.

The unshift() and shift() methods will add and remove, respectively, from the head of the array.

To add or remove one or more element from the middle of the array, use the splice() method.

For searches, indexOf() and lastIndexOf() are available to search using strict equality. See also the ArrayUtilities class methods, provided in the ActionScript 3.0 Cookbook.

Arrays can also be sorted; see the help file for details.

Copying an Array

We can create a shallow copy of an array by calling either the concat() or slice() methods with no arguments.

The following example, from ADOBE FLEX 3 Developer Guide, defines a function named clone() that does deep copying. The function creates a deep copy by serializing the array into an instance of the ByteArray class, and then reading the array back into a new array.

	import flash.utils.ByteArray;
	function clone(source:Object):*
	{
		var myBA:ByteArray = new ByteArray();
		myBA.writeObject(source);
		myBA.position = 0;

		return(myBA.readObject());

	}

Typed Arrays

The article at:

http://livedocs.adobe.com/flex/3/html/help.html?content=10_Lists_of_data_3.html

shows how to implement a strongly typed array, and may be useful in shedding light on use of Class class and the apply method of the Function class.

Flash Player 10 has a strongly typed Vector class; see:

http://blog.skitsanos.com/2008/05/new-vector-actionscript-3s-typed-array.html

Array Collections

Arrays are not compatible with data binding, because they do not provide a mechanism to :

  • dispatch an event when data changes
  • allow listeners to subscribe to these events

The ArrayCollection class meets these requirements with the collectionChange event and the addEventListener method.

An ArrayCollection wraps an Array object.  The ArrayCollection property source points the the underlying Array instance. When constructing an ArrayCollection, you can provide the Array or you can set the source property after construction:

	var myArray:Array = new Array(10); //length=10
	var myColl:ArrayCollection = new ArrayCollection(myArray);
	//Alternatively:
	var myOldArray:Array = new Array(10);
	var myColl:ArrayCollection = new ArrayCollection();
	myColl.source = myOldArray;

Note that if you create an empty ArrayCollection and add elements using the methods of the ArrayCollection rather than assigning an Array (via the source property), an Array is created for you.

One can get a hold of the underlying Array object through this source property and manipulate the array directly, using the methods of the Array class. If you do this, you must use ArrayCollections’s refresh()method to trigger data binding:

	myCollection.source.push("a_string");
	myCollection.refresh();

ArrayCollection is derived from ListCollectionView class,  which implements the ICollectionView and IList interfaces. IList interface  provides add, set, get, and remove operations that operate directly on linear data; these include:

  • addItem(), addItemAt()
  • setItemAt()
  • getItemAt(), getItemIndex()
  • removeItemAt(), removeAll()

ListCollectionView class also allows the use of [ ] array notation to access the getItemAt() and setItemAt() methods.

mx.utils.ArrayUtil package

This class contains two static methods:

  • getItemIndex() returns the index of the item in the array.
  • toArray() ensures that an Object can be used as an Array.

(Compare getItemIndex() with indexOf() method of Array class).

ArrayUtil Class Methods in as3corelib:

as3corlib is an opensource project and can be found at:

http://code.google.com/p/as3corelib/

arrayContainsValue () method :

Determines whether the specified array contains the specified value.

arraysAreEqual () method :

Compares two arrays and returns a boolean indicating whether the arrays contain the same values at the same indexes.

copyArray() method:

Creates a copy of the specified array. Note that the array returned is a new array but the items within the array are not copies of the items in the original array (but rather references to the same items) (note: simply uses slice() for copying).

createUniqueCopy() method:

Create a new array that only contains unique instances of objects in the specified array. Basically, this can be used to remove duplication object instances from an array

removeValueFromArray() method:

Remove all instances of the specified value from the array

ArrayUtilities Class from ActionScript 3.0 Cookbook

You can get the source code at:

http://rightactionscript.com/ascb.

For samples, you will need the book.

Adobe.com also has recipes.


Follow

Get every new post delivered to your Inbox.