ActionScript 3 Singleton Redux

| 14 Comments | No TrackBacks

Not to beat a dead horse, but....

Ever since developers have been using ActionScript 3 the quest for the perfect Singleton has been underway. The heart of the issue is that there are no private constructors in ActionScript 3. Thus, it's been a tricky road trying to find the best way to prevent other developers from inadvertently invoking a Singleton's constructor and creating an additional (and erroneous) instance.

For example, a quick google search yields quite a few results. Here are a handful of them that I've tried to place in chronological order:

What do I think? My initial reaction was to not worry about it. Seriously, what does it matter? Do we really need compile time checking? Isn't runtime checking and unit testing enough? If a developer uses the class wrong, is that the class author's fault? As long as there is documentation as to what the class is and how it's used, then this is really a non-issue at best and trivial at worst.

Admittedly that's a bit of a naive attitude. However, in over a year of not caring about the private constructor issue I can honestly say that I've never run into a problem with singletons, or had any of my team members accidentally use them the wrong way.

It was actually a combination of other factors (and personal preference) that made me revisit the singleton pattern. The singleton technique that I prefer was developed to address the other issues I was running into and to reflect my personal coding style. While I was at it, I figured I might as well address the private constructor issue too. After all, we all love being smacked around by the compiler sometimes.

The technique I prefer has the following highlights:

  • Usage of static instance read-only property instead of a static getInstance() function. This is somewhat a matter of style and personal preference, but I prefer the succinctness of the read-only property. This is especially obvious when the singleton is used in binding expressions. Plus, getInstance() is so 1990s Java which ActionScript is most definitely not. I kid, I kid. But seriously, ".instance" is cooler.
  • Usage of a private lock class to prevent outside construction. While this is a common theme in the above links, my approach is slightly different. Instead of passing an instance of the private locking class to the constructor, I just pass the Class reference itself. This does two things. First, it clarifies the conditional check in the constructor. The test for the proper locking Class reference communicates the code's intent better than the traditional check for not null. Second, it encapsulates the private locking class itself. The constructor's argument is simply lock:Class which doesn't expose the name of the private locking class to the outside world, but still communicates that the constructor is locked.
  • Removal of 'Unable to bind' warnings in Flex 2. When you use a singleton in a binding expression, it's typical to have the Console log flooded with warning messages indicating that binding to the instance property will not be able to detect updates. My singleton version fixes these warnings.
  • Use of const instead of var for the instance storage. This one is pretty obvious, but using const here communicates intent better. The variable storing the singleton instance is not allowed to change so const is the better choice.

So, with that said, I thought it was worth throwing my singleton version into the ring. This is the method I prefer. If you like it, great. If not, that's fine too. No hard feelings. Really.

Sample code is after the jump.

package someProject.model
{

// This import is required for Flex 2
//import flash.events.EventDispatcher;	

[Bindable]
public class Model
	// To avoid binding warnings to "instance" in Flex 2 we need to
	// explicitly extends EventDispatcher and add [Bindable] to the
	// static instance getter. 
	//extends EventDispatcher
{
	
	/** Sample model property.  The name of the currently logged in user. */
	public var userName:String;
	
	// =======================================
	//  Singleton instance
	// =======================================
	
	/** Storage for the singleton instance. */
	private static const _instance:Model = new Model( SingletonLock );
	
	/** Provides singleton access to the instance. */
	// We can use the Bindable metadata with an event name to prevent
	// Flex from reporting that "instance is not bindable".  We have to
	// use a custom event name because you cannot just use [Bindable]
	// with a static function (it's a compiler error).
	//
	// Since we never actually change the instance, we never need to 
	// dispatch an event, so there is no negative side effects here.  If 
	// you're  getting warnings in the console log, try uncommenting the line
	// below.  This isn't necessary with recent Flex 3 builds, but it is for
	// Flex 2.
	//[Bindable( "instanceChange" )]
	public static function get instance():Model
	{
		return _instance;
	}
	
	/**
	 * Constructor
	 * 
	 * @param lock The Singleton lock class to pevent outside instantiation.
	 */
	public function Model( lock:Class )
	{
		// Verify that the lock is the correct class reference.
		if ( lock != SingletonLock )
		{
			throw new Error( "Invalid Singleton access.  Use Model.instance." );
		}
		
		// Normal construction can continue here
		userName = "sample user";
	}
	
} // end class
} // end package

/**
 * This is a private class declared outside of the package
 * that is only accessible to classes inside of the Model.as
 * file.  Because of that, no outside code is able to get a
 * reference to this class to pass to the constructor, which
 * enables us to prevent outside instantiation.
 */
class SingletonLock
{
} // end class

This still doesn't feel right to me. I don't like the private locking class as I think it's a bit of a hack. But, the compile time and runtime checking is a nice feature to help prevent mistakes. Additionally, the singleton related code in the class takes away from the actual meat of the class itself. I want the class to be a Singleton, but I don't want to have to wade through the Singleton code when I'm working on it. I'm also tempted to remove the get instance and just make it public static const instance. The compiler will prevent assignment to const so the read-only property is a little redundant.

I think my ideal situation would be to introduce new [Singleton] metadata that would automatically take care of the implementation details. The metadata is self documenting as it clearly indicates that the class is intended to be a singleton. The compiler would be able to write the singleton related code for us automatically so that we don't have to do it ourselves and so that it doesn't get lost in the actual meat of the class.

Here's an example of what I envision:

[Singleton( "get instance" )]
// or, if you really want to use getInstance() instead...
//[Singleton( "getInstance()" )]
[Bindable]
public class Model
{
	
	/** Sample model property.  The name of the currently logged in user. */
	public var userName:String;
	
	/**
	 * Constructor
	 */
	public function Model()
	{
		userName = "sample user";
	}
	
} // end class
} // end package

How cool is that? We clearly mark the class as a singleton and provide the mechanism we want to use to access the singleton instance (either a read-only property, or a static accessor). Then, we let the compiler do the work behind the scenes. I think this ends up being a really clean and elegant solution.

Obviously this doesn't work today because it would need modifications to the mxmlc compiler. I've submitted this as enhancement request ASC-3033. However, since Flex is going open source this is something we could build in our own if we really wanted to, in theory. Food for thought...

Anyway, enjoy!

No TrackBacks

TrackBack URL: http://www.darronschall.com/mt/mt-tb.cgi/155

14 Comments

I generally go with the "don't worry about it" approach, but still feel like I should do something. Generally, I would prefer something that throws compile errors over run-time, in which case passing an instance of the private class seems best, backed up with a run-time check for null.

Hoping they address this in later versions.

Why not simplify it down to this?

package {
public class MySingleton {
public static const _instance:MySingleton = new MySingleton();
public function MySingleton() {
if ( _instance != null ) { throw new Error( "Please use the instance property to access." ); }
}
public static function get instance():MySingleton {
return _instance;
}
public function testing():void {
trace( "Testing called." );
}
}
}


Testing it with the following shows you cannot create your own instance:

MySingleton.instance.testing();
try { var s:MySingleton = new MySingleton(); }
catch ( ex:Error ) { trace( "Error creating singleton : " + ex.message ); }

Hi Mike,

The biggest reason is that I wanted to have an additional required argument for the constructor. By not having a "lock" argument, you can call MySingleton() without getting any errors from the compiler, and you don't know that you've made a mistake until you test.

By having the lock argument, you're forced to at least acknowledge that the constructor takes an argument. Not passing one will yield a compile-time error. If you see it's an argument called "lock" in the code hints in FlexBuilder, that will clue you in that you're going down the wrong path. If you try and pass null then you're purposefully trying to beat the system, and in that case you'll get the runtime error instead.

That makes sense. If you're just looking for that, you could expand my example just a tad to provide both and without the extra class?

public static const _instance:MySingleton = new MySingleton( new Object() );

public function MySingleton( lock:Object ) {
if ( _instance != null ) { throw new Error( "Please use the instance property to access." ); }
}

Sure, I don't see anything wrong with that, other than that the meaning of the conditional in the constructor changes. I prefer the explicit "test for a certain type of object" condition because it's clearer (more purposeful) than a null check.

Everyone has their own opinion on the matter though. Ultimately, mine is that [Singleton] is a clean/elegant solution that I hope gets implemented eventually. :-)

Just wondering, what can you do with a Singleton that you can't do with a class that has all static methods and properties?

For starters, you can't bind correctly to the static properties. Binding requires an instance so that there's something to dispatch an event from to trigger the binding updates.

What about the technique mentioned by Cédric Néhémie in a comment from Grant Skinner's blog in the link you posted?

It provides compile-time protection without having to worry about getInstance or an instance property or checking for an existing instance. You just access the methods and properties of the instance directly.

I always use that when I want a Singleton/Static class.

Not sure what happened with the characters in my post above - that name should be Cedric Nehemie, but with french accented characters.

Hi Derek,

I don't like that approach because it loses the meaning of the Singleton pattern. The way the code is written, it looks like you're accessing static methods/properties on a class. I know that that's not actually what is happening, but it's really easy to be misconstrued (which is bad).

I prefer "instance" or "getInstance()" because its true to the pattern and communicates the code's intent better.

That's a good point. Indeed (the Binding). The reason I ask, is that "Singleton discussion" has popped up in 4 totally unrelated situations in the past week:

1) Last Friday, With some Java developers at work (who shun the Singleton). We were looking at Cairngorm, and (as Grant Skinner posted a long time ago), there is no need for CairngormEventDispatcher to be one. (I should have had an alarm go off about Binding).

2) Monday in Peter Elsts entry : http://www.peterelst.com/blog/2007/11/24/actionscript-30-design-patterns/

3) Tuesday, In this (old) blog entry (I kind of like the last guys comment) : http://geekglue.b-l-o-g-s-p-o-t.com/2007/10/cairngorm-vs-puremvc-quick-comparison.html (added dashes to the url so it would validate)

4) Finally, Yesterday this posting.


I'm debating the merits of Singletons, weather it really is "the ultimate pattern for n00bs to pat their own backs with".

So, it's a valid pattern in Flex thanks to Binding. How about in the context of an AS3 project? Singeltons are exclusively for data classes... right? Would you ever have one that extends a DisplayObject or so?

Anyway, I like your solution (the static "instance"). Nice one. getInstance() is icky :D

Nice. I will have to give this a spin. I don't really like the approach I'm using at the moment because it clutters up my class with a lot of extra code?

Has anyone had any success trying to make Singleton an Interface?

Good thoughts, Darron.

I've certainly used the pattern in a fair share of projects in the past, but anymore I'm pretty anti-Singleton. Rather than have components in a module binded directly to a Singleton application model for instance, I instead bind the module to the application model (not a Singleton) and then the components bind to the module. Sure, it's a little extra work, but it's much cleaner and promotes loose-coupling.

I realize this post is geared towards those who are ok with using the pattern and are in search of the best way to implement it in AS3, but I just thought I'd throw my two cents into the mix.

Nice! I like it. (I mean, I don't like it as much as I like having private constructors, but....)

This also works well for enumeration classes, e.g.:

package {
import flash.errors.IllegalOperationError;
public final class RecordAction {
public function RecordAction(lock:Class) {
super();
if (lock != Lock) {
throw new IllegalOperationError("Cannot instantiate RecordAction. Use static constants instead.");
}
}
public static const CREATE:RecordAction = new RecordAction(Lock);
public static const DELETE:RecordAction = new RecordAction(Lock);
public static const RETRIEVE:RecordAction = new RecordAction(Lock);
public static const UPDATE:RecordAction = new RecordAction(Lock);
}
}
class Lock {
}

Leave a comment



About this Entry

This page contains a single entry by darron published on November 29, 2007 11:20 AM.

Hooking dispatchEvent for Cairngorm Events was the previous entry in this blog.

Launching Firefox from ANT on OSX is the next entry in this blog.

Find recent content on the main index or look in the archives to find all content.

Archives

OpenID accepted here Learn more about OpenID
Powered by Movable Type 5.02