PDA

View Full Version : ActionScript 3 Singleton


rawmantick
12-22-2008, 06:18 AM
I've been meeting several solutions of implementing singleton classes in AS3. SInce we cannot set the constructor as private, many "hacks" have the right to appeart. However, the most commonly used variant (which is described in ActionScript 3.0 Design Patterns from O'Reilly (http://oreilly.com/catalog/9780596528461/)) is very weird to my opinion. The constructor requires some class, which can only be the private one, being hidden from another parts of the program.
The common situation is: the developer meets the class. He(she) wants to instantiate it and gets runtime error like "use getInstance instead". And he(she) does. But what the hack, I need to pass some sort strange and unknown class... It will realy make the developer jump into 5 minutes of thinking "what???".

Probably I won't invent anything. But a very easy and ellegant way if "singletoning" is offered:
public function SingletonClass
{
static public function getInstance():SingletonClass
{
if( _instance == null )
{
_allowCallConstructor = true;
_instance = new SingletonClass();
_allowCallConstructor = false;
}
return _instance;
}

static private var _instance:SingletonClass = null;
static private var _allowCallConstructor:Boolean = false;

public function SingletonClass()
{
if( !_allowClassConstructor )
throw new Error("Use getInstance() method instead");
...
}
}

creynders
12-22-2008, 08:37 AM
All singleton implementations have several drawbacks and other benefits.
This one has as a drawback that it doesn't throw any compile-time errors if you DO try to instantiate. Hence the use of the internal class that you've seen in the other implementations.
However, you're incorrect in thinking that you need to use it in conjunction with getInstance. It provides a compile-time checking mechanism and as the "user" of the singleton class you don't need to do anything with the internal class.
Here's the basic implementation:

package {
public class SingletonClass {
static private var instance : SingletonClass;

static public function getInstance() : SingletonClass {
if ( instance == null ) instance = new SingletonClass( new Lock() );
return instance;
}

public function( lock : Lock ) : void {
if ( lock == null ) throw new Error( "not allowed bla bla bla ..." );
}

}
}

internal class Lock{}

You'll use it like this:

SingletonClass.getInstance().someMethod();

However if you'd try to do this

s : SingletonClass = new SingletonClass()

You'd get a Compile Time Error saying a required parameter has not been provided.
I think that's an added benefit, but of course that's a matter of taste.

rawmantick
12-22-2008, 09:19 AM
Anyway since having got a private constructor we would start to feel free of these hacks...

// not only me putting static before access specifier )))

newblack
12-22-2008, 01:42 PM
i've been too lazy for a long time to do anything in the constructor- it doesn't end up being worth it in the end. how many times in the development of your application has that error gotten thrown apart from testing your singleton implementation itself?

that said, i have to say i don't like romantique's implementation- you're choosing to store a boolean that only ever equates to whether or not _instance is defined or null. and especially since you do that check anyhow, the boolean is superfluous.

rawmantick
12-22-2008, 06:46 PM
The variable is not superflous. And you are not right about the boolean. It's for another thing. It is a key whether it's allowed to use constructor or not. And not for checking if the instance is already created or not. Anyway... after minutes of rethinking I agree with creynders - my variant goes for runtime, which is not commonly used. The more common situation is checking "singleton" at compile.

Eh... anyway, I don't use singletons too often) And to say generaly - who realy cares which way to go if it works:)

newblack
12-22-2008, 07:02 PM
it is superfluous. at least how you're using it here. the condition only represents whether the instance is null or not. it is the exact same thing as throwing an error in the constructor if _instance == null.

rawmantick
12-22-2008, 08:02 PM
With this boolean you cannot call a constructor from anywhere, only from where you can change that boolean - from getInstance() method.

In getInstance() I check if the instance already exists. If so - I return it. If not - I allow instantiating only for one and the only one time, instantiate and finaly forbid it forever.

Checking for null is for single instance. Checking for boolean value is for accessing constructor.

You can draw a state diagram with all the possible state sets and you will see, that there are situations, when instance==null and allowCallConstructor==true conditions are not always together of the same value. Which absolutely prove tha fact, that the boolean is not superflous. It just has another thing to control.

I am sure.

// update
it is the exact same thing as throwing an error in the constructor if _instance == null

Ok. The instance is null. And you throw an error if an instance is null from constructor. You use getInstance() instead. Inside getInstance() you try to instantiate. But when you try to instantiate - you call a constructor. Inside this call instance is still null. The constructor throws an error anyway, no matter if you call it from somewhere of from getInstance. That's what you are describing. And that's exactly what the boolean is for to resolve the cycle. I think this is obvious. Don't you think? I don't see if it's possible for an example you've described to work. I've tested my one. Yes it does work. Well... ofcourse if I haven't missed anything from your words:)

Sory for my english...

newblack
12-22-2008, 08:14 PM
haha, i'm sorry you had to write all that, i've been eating knuckle sandwiches again, of course what i've suggested wouldn't work.

all of that said, i do think it seems like too much effort still... but sorry for the hassle!

rawmantick
12-22-2008, 08:17 PM
Anyway thank you guys newblack and creynders for discussion and opinions :)

creynders
12-24-2008, 10:16 AM
Anyway since having got a private constructor we would start to feel free of these hacks...

// not only me putting static before access specifier )))

Ah yes, don't you think that's a lot clearer and more readable?
IMO something which is noteworthy (like a property being static, which is a huge difference) should be most visible and draw attention to itself.

rawmantick
12-24-2008, 12:20 PM
Yes, i think so:) In fact I have like a table of specifiers, sorted by their importance. Like it's more important for me if the class member is static or not than if it's for example overridden or not. So I put statics first, and put the static keyword first. Then there go an access specifier. Public, protected and then private. So the keyword is the second and the member sorting is corresponding. Then there go override specifier and so on...

I love to have a system everywhere :) Damn, I gotta learn less math..:o