LiraNuna's Development Blog
Typesafe assignable enumerations in AS3
Posted on Monday 28 July 2008

Being a huge C/C++ fan, I had a really hard time switching to AS3 and giving up most of C++’s power features as enumerations.

I was surprised that a programming language that is based on Java and C# doesn’t support native enumerations built in the language. After a quick look-up at various Google searches, turns out no one has implemented a type-safe assignable enumerations design pattern in AS3. The various code examples I’ve seen were either not type safe or not assignable (using the enumerations as ‘global’ consts). Since those were not the behaviors I wanted, I had to write my own.

One major problem I was facing was how to shadow the data of the enumerations, just like C++ does (although in C++ they could be used as integers as well). Using integers was out of the question and using strings would be more of a resource hog than helper.

The solution is recursive declaration – declare a class, which has itself on the inside using recursive constructor (a constructor that receives ‘itself’, much like copy constructor in C++).

This may sound crazy, but it actually works – Flash IDE does not complain and the result is a type-safe assignable type that you can only assign a set of specific values to.

This following code is an example of a ‘Direction’ enumeration written in AS3 and I can’t see any reason why not use it, this simple structure enables you to:

  • Declare a class typed ‘Direction’
  • Set the declared variable to a specific set of values predefined in the class
  • Check and compare the variable (using either a boolean condition or a switch statement) to the predefined set of values
  • Shadowing of the values to an abstract data, meaning that unlike C++, you cannot preform arithmetic operations on it

And here is the code, commented:

package
{
	class Direction
	{
		/*
		 * The actual enumeration values. Note that the sorting order doesn't matter.
		 */
		public static const NONE:Direction	= new Direction(NONE);
		public static const UP:Direction	= new Direction(UP);
		public static const DOWN:Direction	= new Direction(DOWN);
		public static const LEFT:Direction	= new Direction(LEFT);
		public static const RIGHT:Direction	= new Direction(RIGHT);
 
		/* Constructor */
		public function Direction(d:Direction)
		{
			/*
			 * Empty fake constructor
			 * The part that matter is that it accepts a 'copy' of itself
			 * For the recursive assignment to work
			 */
		}
	}
}

The reason the above code uses the ‘recursive’ constructor structure, is to ensure type safety. When assigning a new Direction type, only the above predefined list of values can be assigned. Another reason is, when you declare a function that takes a direction, you eliminate the possibility to invoke the function with ‘new Direction()’ as an argument and passing an undefined value (Direction.NONE should be used for that).

The constructor only requires one argument, which is typed as Direction as well, eliminating any possible casts to another type, shadowing the actual data (a reference to self) inside the class, making it a true type safe implementation.

Since in AS3, everything must be an object (a class), this leads to some interesting options, such as ‘helper functions’ which could be embedded inside the ‘enum’ itself, for example, the Java-like ‘toString’ function, could be easily implemented inside the Direction class as:

public function toString()
{
	switch(this) {
		case Direction.UP:
			return "Up";
		case Direction.DOWN:
			return "Down";
		case Direction.LEFT:
			return "Left";
		case Direction.RIGHT:
			return "Right";
		default:
			/* Direction.NONE is considered 'undefined' (no direction) */
			return "undefined";
	}
}

Now you can do anything an enueration was designed to do:

var dir:Direction = Direction.UP;	// Legal, Direction.UP is valid.
dir = 0;				// Illegal, '0' is not in the predefined set of values
trace(dir.toString());			// Will print 'Up' if above method is used

There you have it – a type safe assignable enumeration implementation in AS3.


7 Comments for 'Typesafe assignable enumerations in AS3'

  1.  
    justin
    September 15, 2008 | 14:36
     

    you should declare the class as final, so it can not be extended to override anything you’ve done.

  2.  
    Alex Russell
    February 27, 2009 | 23:18
     

    Thanks for this! Really useful.

  3.  
    sameer
    August 12, 2009 | 12:44
     

    instead of the switch statement inside toString() how about have a instance variable _value and pass in the hard-coded value through the constructor:
    public function Direction(d:Direction, value:String) {
    this._value = value
    }

    and return _value inside toString() method. Would this work?

  4.  
    Mohan
    October 28, 2009 | 9:58
     

    Was quite useful, especially Sameer’s comment. I think I’d go with that :)

  5.  
    wyrmmage
    December 2, 2009 | 10:33
     

    Very useful!

    Thank you for this :)

  6.  
    chris
    January 10, 2011 | 3:07
     

    what’s stopping you from passing in “null” into the constructor?

  7.  
    September 27, 2011 | 19:58
     

    Great work!! I combined sameer’s and chris’ ideas above. I ran a few tests and it appears to work the same and doesn’t require the recursive constructor:

    public class Direction
    {

    public static const NONE:Direction = new Direction(“undefined”);
    public static const UP:Direction = new Direction(“UP”);
    public static const DOWN:Direction = new Direction(“DOWN”);
    public static const LEFT:Direction = new Direction(“LEFT”);
    public static const RIGHT:Direction = new Direction(“Right”);

    private var _value:String;

    public function Direction(value:String)
    {
    this._value = value;
    }

    public function toString():String
    {
    return _value;
    }

    }

Leave a comment

(required)

(required)


Information for comment users
Line and paragraph breaks are implemented automatically. Your e-mail address is never displayed. Please consider what you're posting.

Use the buttons below to customise your comment.


RSS feed for comments on this post | TrackBack URI